Git path · Working with others · Topic 8 of 13

Remotes, fetch and pull: tracking branches

Not started

A remote is a named URL for another copy of the repository; git clone names the one you cloned from origin. When you fetch, Git downloads the objects you don't have and records where each of the remote's branches points as a remote-tracking ref, such as origin/main under refs/remotes/. Those refs are local snapshots that change only when you fetch. Your own main is a separate branch that tracks origin/main, its upstream.

Why it matters: Knowing that origin/main is a local, possibly stale snapshot explains most 'but it works on my machine' and 'why is my branch behind' moments.

  1. 1A remote is a URL with a name

    origin is just the default name clone gives the repository you cloned from.

  2. 2origin/main is a local ref

    Remote-tracking refs record where the remote's branches were the last time you fetched. They only change when you fetch.

  3. 3fetch downloads, pull also integrates

    git fetch updates origin/* and touches nothing else. git pull is fetch followed by a merge, rebase or fast-forward.

  4. 4Upstream links a branch to its remote

    Your main tracks origin/main, so status can say ahead or behind and plain pull and push know where to go.

1

How it works

The explanation, with examples you can run.

Two clones and a server

A bare repository (no working tree) plays the server. Alice pushes twice; Bob has only the first commit.

cd /tmp && mkdir demo && cd demogit init -q --bare -b main origin.gitgit clone -q origin.git alice 2>/dev/nullgit -C alice commit -q --allow-empty -m "First"git -C alice push -q -u origin maingit clone -q origin.git bobgit -C alice commit -q --allow-empty -m "Second"git -C alice push -qcd bobgit status -sb
## main...origin/main

Bob's status says he is level with origin/main. That is true of his local snapshot, which is an hour old in real life. Fetch updates it:

git fetchgit status -sbgit branch -vvgit log --oneline main..origin/main
From /tmp/demo/origin   dd0b14a..fb15038  main       -> origin/main## main...origin/main [behind 1]* main dd0b14a [origin/main: behind 1] Firstfb15038 Second

The fetch line shows origin/main moving. Bob's main and his files did not change. main..origin/main lists commits on the remote that he doesn't have yet. He can integrate them whenever he wants:

git merge --ff-only origin/main
Updating dd0b14a..fb15038Fast-forward

The configuration behind it

git config --get-regexp '^(remote\.origin|branch\.main)\.'
remote.origin.url /tmp/demo/origin.gitremote.origin.fetch +refs/heads/*:refs/remotes/origin/*branch.main.remote originbranch.main.merge refs/heads/main

The fetch refspec says "copy every branch under refs/heads/ on the remote to refs/remotes/origin/ here". The branch.main.* lines are the upstream: they are what make git status report ahead and behind, and what plain git pull and git push use. git push -u origin feature or git branch --set-upstream-to=origin/feature sets them for a new branch.

Pull is fetch plus integrate

git pull runs git fetch, then integrates the upstream into your current branch. If you have no local commits, that is a fast-forward. If both sides have new commits, current Git refuses to guess and asks you to choose with --rebase, --no-rebase (merge) or --ff-only, or with the pull.rebase and pull.ff settings. Many developers set git config --global pull.rebase true so their unpublished commits are replayed on top instead of producing a merge commit every time they pull.

Some useful extras: git fetch --prune (or fetch.prune=true) deletes remote-tracking refs for branches deleted on the server, git remote -v lists remotes, and you can add more, such as upstream for the original project when you work on a fork.

2

Check yourself

3 questions. Get them all right to finish this topic.

  1. 1.git status says 'Your branch is up to date with origin/main', but a teammate pushed an hour ago. Why?
  2. 2.What does git fetch change in your repository?
  3. 3.Your local main and origin/main have both gained commits, and pull.rebase is not set. What does a recent Git do on git pull?

0 of 3 right so far. Get all three to finish this topic.