Git-Mastery: Lessons

Tour 3: Working With an Existing Remote Repo

Target Usage: To work with an existing remote repository.

Motivation: You will often need to start with an existing remote repository. You may need to create your own copies and keep them updated when the upstream repository changes.

Lesson plan:

GitHub allows you to create your own remote copy of another repo through a process called forking.

   T3L1. Duplicating a Remote Repo on the Cloud covers that part.

The next step is to create a local copy of the remote repo by cloning it.

   T3L2. Creating a Local Copy of a Repo covers that part.

When there are new commits in the remote repo, you need to pull those commits down to your local repo.

   T3L3. Downloading Data Into a Local Repo covers that part.

T3L1. Duplicating a Remote Repo on the Cloud


GitHub allows you to create your own remote copy of another repo through a process called forking.

This lesson covers that part.

A fork is a copy of a remote repository created on the same hosting service, such as GitHub, GitLab, or Bitbucket. On GitHub, you can fork a repository owned by another user or organization into your own space, such as your account or an organization where you have the required access. Forking is useful when you want to experiment with a repo but don't have write permissions to the original; it gives you your own remote copy without affecting the original repo.

HANDS-ON: Forking a repo on GitHub

Preparation Create a GitHub account if you don't have one yet.

1 Go to the GitHub repo you want to fork, e.g., samplerepo-things

2 Click the button in the top-right corner. On the next screen:

  • choose your own account or a GitHub organization where you are an admin.
  • uncheck the [ ] Copy the main branch only option, so that you get copies of other branches (if any) in the repo. You'll learn more about branches in a later lesson.

done!

Forking is not a Git feature, but a feature provided by hosted Git services like GitHub, GitLab, or Bitbucket.

GitHub does not allow you to fork the same repo more than once to the same destination. If you want to re-fork, you need to delete the previous fork.

EXERCISE: fork-repo


T3L2. Creating a Local Copy of a Repo


The next step is to create a local copy of the remote repo by cloning it.

This lesson covers that part.

You can clone a repository to create a local copy on your computer. A normal clone downloads the repository history and populates the working directory with the files from the latest commit of the default branch, giving you a local working copy.

Cloning a repo automatically creates a remote named origin, which points to the repo you cloned from.

Conventions:

When configuring remotes for a Git repository, the following naming conventions are commonly used:

  • origin: The repository that you cloned from is usually given the remote name origin. Git sets this remote name automatically when you clone a repository (but you can change it to something else).
  • upstream: In fork-based workflows, the repository you forked from is often added as a second remote named upstream. This name is not created by Git automatically; it is a convention chosen by developers. Some teams use a more specific name for this, such as team-repo.

Separately from remote names, the term 'upstream' is also used informally to describe the relationship between an original repository and its duplicates. When one repository is created by duplicating another (for example, by forking or cloning), the original repository is said to be upstream of the duplicate.

Example:

  • If you fork R1 to create R2, then R1 is upstream of R2.
  • If you then clone R2 to create R3, both R1 and R2 are upstream of R3.
HANDS-ON: Cloning a remote repo

1 Clone the remote repo to your computer. For example, you can clone the samplerepo-things repo, or the fork you created from it in a previous lesson.

Note that the GitHub project page URL is different from the repo URL you need for cloning. For example:

https://github.com/git-mastery/samplerepo-things  # GitHub project URL
https://github.com/git-mastery/samplerepo-things.git # the repo URL
 CLI

You can use the git clone <repository-url> [directory-name] command to clone a repo.

  • <repository-url>: The URL of the remote repository you want to copy.
  • [directory-name] (optional): The name of the folder where you want the repository to be cloned. If you omit this, Git will create a folder with the same name as the repository.
git clone https://github.com/git-mastery/samplerepo-things.git  # if using HTTPS
git clone git@github.com:git-mastery/samplerepo-things.git  # if using SSH

git clone https://github.com/foo/bar.git my-bar-copy  # also specifies a dir to use

For exact steps, see this GitHub document.

Sourcetree on Windows

FileClone / New ... and provide the URL of the repo and the destination directory.

Sourcetree on macOS

FileNew ... → Choose as shown below → Provide the URL of the repo and the destination directory in the next dialog.

2 Verify the clone has a remote named origin pointing to the repo you cloned from.

 CLI

Use the git remote -v command that you learned earlier.

Sourcetree

Choose the RepositoryRepository Settings menu option.

done!

EXERCISE: clone-repo


T3L3. Downloading Data Into a Local Repo


When there are new commits in the remote repo, you need to pull those commits down to your local repo.

This lesson covers that part.

Bringing changes from a remote repository into a local repository involves two steps: fetch and merge.

  • Fetch is the act of downloading the latest changes from the remote repository, but without applying them to your current branch yet. It updates metadata in your repo so Git knows what has changed in the remote repo, but your own local branch remains untouched.
  • Merge is the step after fetching that incorporates the fetched changes into your local branch. It combines your local branch with the changes from the corresponding branch in the remote repo.
HANDS-ON: Fetch and merge from a remote

Scenario You have cloned a remote repo. After you cloned it, two new commits were added to the remote. R and L1 in the diagram below represent this scenario.

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "add assets.txt"
    commit id: "add goals.txt"
    commit id: "[HEAD → main] add loan to Chang"

[R: Remote repo origin]

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "[HEAD → main][origin/main] add assets.txt"

[L1: Local repo
currently,
2 commits behind the remote]

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "add assets.txt"
    commit id: "add goals.txt"
    commit id: "[HEAD → main][origin/main] add loan to Chang"

[L2: Local repo
after downloading
the missing commits]

Target Now, you want to bring those missing commits into your clone, taking it from state L1 to state L2 (as shown in the diagram above).

Preparation

Option 1: Create a fresh sandbox using the Git-Mastery app

  • Navigate inside the gitmastery-exercises folder.
  • Run the gitmastery download hp-fetch-merge command.

The sandbox will be set up inside the gitmastery-exercises/hp-fetch-merge folder.


Option 2: Manually set up a sandbox

To create the initial remote and local states (R and L1 above), use these steps.

  1. Clone the repo git-mastery/samplerepo-finances. It has 3 commits. Your clone now has a remote origin pointing to the remote repo you cloned from.
  2. Change the remote origin to point to samplerepo-finances-2. This remote repo is a copy of the one you cloned, but it has two extra commits.
 CLI
git remote set-url origin https://github.com/git-mastery/samplerepo-finances-2.git
Sourcetree

Go to RepositoryRepository settings ... to update remotes.


1 Verify Git has not yet learned about the extra commits in the remote.

 CLI
git status
On branch main
Your branch is up to date with 'origin/main'.

nothing to commit, working tree clean
Sourcetree

The revision graph should look like this:

If it looks like the image below, Sourcetree may be auto-fetching data from the repo periodically.

2 Fetch from the new remote.

 CLI

Use the git fetch <remote> command to fetch changes from a remote. If you do not specify <remote>, Git uses the default remote origin.

git fetch origin
remote: Enumerating objects: 8, done.
... # more output ...
   afbe966..b201f03  main     -> origin/main
Sourcetree

Click on the Fetch button on the top menu:

Sourcetree top menu

3 Verify the fetch worked: the local repo is now aware of the two missing commits. Also observe that the local main branch ref, the staging area, and the working directory remain unchanged after the fetch.

 CLI

Use the git status command to confirm the local repo now knows it is behind the remote repo.

git status
On branch main
Your branch is behind 'origin/main' by 2 commits, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean
Sourcetree

Now, the revision graph should look something like this. Note how the origin/main ref is now two commits ahead of the main ref.

4 Merge the fetched changes.

 CLI

Use the git merge <remote-tracking-branch> command to merge the fetched changes. Check the status and the revision graph to verify that the branch tip has now moved by two more commits.

git merge origin/main
Updating afbe966..b201f03
Fast-forward
 goals.txt | 1 +
 loans.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 goals.txt

Verify the status of the repo is as expected:

git status
On branch main
Your branch is up to date with 'origin/main'.
git log --oneline --decorate
b201f03 (HEAD -> main, origin/main, origin/HEAD) Add loan to Chang
1b923a4 Add goals.txt
afbe966 Add assets.txt
0434002 Add loan to Ben
fd96227 Add loans.txt
Sourcetree

To merge the fetched changes, right-click on the latest commit on the origin/main branch and choose Merge.

In the next dialog, choose as follows:

The final result should look something like this, matching state L2 in the diagram above:

Note that merging fetched changes can get complicated when the repo has multiple branches, or when local commits conflict with remote commits. We will address such situations in a later lesson when we learn more about Git branches.

done!

Pull is a shortcut that combines fetch and merge: it fetches the latest changes from the remote and immediately merges them into your current branch. In practice, Git users usually pull instead of fetching and merging separately.

pull = fetch + merge

HANDS-ON: Pull from a remote

Scenario Use the same scenario as the previous hands-on practical.

Target Use the same target as in the previous hands-on practical, but fetch and merge in one step.

Preparation

Option 1: Create a fresh sandbox using the Git-Mastery app

  • Navigate inside the gitmastery-exercises folder.
  • Run the gitmastery download hp-pull-remote command.

The sandbox will be set up inside the gitmastery-exercises/hp-pull-remote folder.


Option 2: Manually set up a sandbox

Set up the same scenario as in the previous hands-on practical, but use a different local folder.


1 Pull the newer commits from the remote instead of fetching and merging separately.

 CLI

Use the git pull <remote> <branch> command to pull changes.

git pull origin main
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 6 (delta 1), reused 6 (delta 1), pack-reused 0 (from 0)
Unpacking objects: 100% (6/6), 557 bytes | 69.00 KiB/s, done.
From https://github.com/git-mastery/samplerepo-finances-2
 * branch            main       -> FETCH_HEAD
   afbe966..b201f03  main       -> origin/main
Updating afbe966..b201f03
Fast-forward
 goals.txt | 1 +
 loans.txt | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 goals.txt

The following command also works. If you do not specify <remote> and <branch>, Git will pull into the current branch from the remote branch it tracks.

git pull
Sourcetree

Click on the Pull button on the top menu:

Sourcetree top menu

In the next dialog, choose as follows:

2 Verify that the outcome matches the fetch + merge steps you did in the previous hands-on practical.

done!

You can pull from multiple remote repos, as long as the repos have a shared history. This is useful when the upstream repo you forked from has new commits that you want to bring into your fork and local repo.

HANDS-ON: Sync your repos with the upstream repo

Scenario You have forked and cloned a remote repo. Since then, new commits have been added to the original remote repo that you forked from.

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "add assets.txt"
    commit id: "add goals.txt"
    commit id: "[HEAD → main] add loan to Chang"

[upstream: the original remote repo
that you forked]

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "[HEAD → main] add assets.txt"

[origin: your fork (remote),
2 commits behind upstream]

gitGraph BT:
    %%{init: { 'theme': 'default', 'gitGraph': {'mainBranchName': 'main'}} }%%
    commit id: "add loans.txt"
    commit id: "add loan to Ben"
    commit id: "[HEAD → main][origin/main] add assets.txt"

[your clone (local), also
2 commits behind]

Target Now, you want to bring the new commits into your clone and then update your fork with them.

Preparation

Create a fresh sandbox using the Git-Mastery app

  • Navigate inside the gitmastery-exercises folder.
  • Run the gitmastery download hp-sync-upstream command.

The sandbox will be set up inside the gitmastery-exercises/hp-sync-upstream folder.


1 Confirm your local repo is behind upstream by two commits. Here are two ways to do that:

a) Go to the upstream repo at https://github.com/git-mastery/samplerepo-finances-2, and navigate to the repo's commit list. Compare that list with the commits in your local copy.
OR
b) Do a fetch and examine the revision graph locally, as shown below.

git fetch upstream
git log --oneline --decorate --graph --all
* b201f03 (upstream/main, upstream/HEAD) Add loan to Chang
* 1b923a4 Add goals.txt
* afbe966 (HEAD -> main, origin/main, origin/HEAD) Add assets.txt
* 0434002 Add loan to Ben
* fd96227 Add loans.txt

2 Pull from the upstream repo. Git will bring any new commits into your local repo. For example:

git pull upstream main

3 Push to your fork. Any new commits you pulled from the upstream repo will now appear in your fork as well. For example:

git push origin main

This method is the standard way to synchronize a fork with the upstream repo. Platforms such as GitHub also provide alternatives, including GitHub's Sync fork feature.

done!

SIDEBAR: Distributed vs Centralized Revision Control

Revision control can follow either a centralized or a distributed model.

Centralized RCS uses a single central (server-hosted) repository that is shared by the team. Developers check out a working copy, make changes locally, and then commit directly to the central repository. Developers do not have their own copy of the entire repository history; they only have a working copy of files. One advantage of this model is having one clear "source of truth." A major disadvantage is that the central server becomes a critical dependency: if it's down, most operations (commits and history queries beyond the local working copy) are blocked. Older RCS tools such as CVS, Subversion, and Perforce follow this model.

The centralized RCS approach

Distributed RCS (also known as decentralized RCS) allows multiple remote and local repositories to work together. Workflows vary by team. For example, each team member can have their own remote repository in addition to a local repository. This architecture enables offline work, fast local operations, and more flexible workflows. It also supports multiple integration points (e.g., forks or alternative remotes) and uses cryptographic checksums to ensure history integrity. The trade-offs include more conceptual complexity (multiple repositories, remotes, and sync patterns) and the need for conventions to establish an authoritative integration flow. Git and Mercurial are prominent RCS tools that support the distributed approach.

The decentralized RCS approach

Because Git uses multiple copies of a repository, Git is considered a distributed revision control system, as opposed to a centralized revision control system that keeps only a single repository.

EXERCISE: fetch-and-pull

DETOUR: Pulling from Multiple Remotes

You can pull from any number of remote repos, as long as the repos have a shared history.

  1. Add the GitHub repo URL as a remote using a suitable name, such as upstream, central, production, or backup, if you haven't done so already.
  2. Pull (or fetch) from that remote, remembering to select the correct remote.
 CLI

For example, git pull backup main

Sourcetree

Similar to before, but remember to choose the intended remote to pull from.



At this point: Now you can create your own remote and local copies of any accessible GitHub repo you are allowed to fork or clone, and update your copy when there are new commits in the upstream repo.

What's next: Tour 4: Using the Revision History of a Repo