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/mainBob'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/mainFrom /tmp/demo/origin dd0b14a..fb15038 main -> origin/main## main...origin/main [behind 1]* main dd0b14a [origin/main: behind 1] Firstfb15038 SecondThe 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/mainUpdating dd0b14a..fb15038Fast-forwardThe 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/mainThe 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.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.