The difference between git pull and git fetch
git pull is git fetch followed by a merge. That one sentence is the whole
answer, and it is easier to trust once you have watched what each half does to
your repository.
fetch moves one pointer and nothing else
before fetch: local main ea0365c origin/main ea0365c
after fetch: local main ea0365c origin/main a087a00 <- moved
file.txt one| <- unchanged
git fetch downloads the new commits and
updates origin/main, the remote-tracking ref. Your branch does not move. Your
files do not change. Afterwards your repository knows about work it has not
adopted.
That is the whole difference. origin/main is git’s note of where the remote
was; main is where you are.
Which is what lets you look before you leap
$ git log main..origin/main
a087a00 colleague commit
$ git diff --stat main origin/main
file.txt | 1 +
1 file changed, 1 insertion(+)
The main..origin/main range means “commits on the remote that I do not have”.
This is the actual argument for fetching rather than pulling: on an unfamiliar
repository, or before a release, you get to read what arrived before it lands in
your working tree.
pull does the second half too
$ git pull
after pull: local main a087a00 file.txt one|two|
Same result you would get from fetch followed by merge. On a branch that has
not diverged this is a fast-forward — your branch pointer simply advances, and
no merge commit is created.
When both sides have moved
If you committed locally and the remote moved, there is nothing to fast-forward and git has to combine the two histories:
--no-rebase: --rebase:
* 17ec289 Merge... * fb288d3 my local commit
|\ * a087a00 colleague commit
| * a087a00 colleague * ea0365c first commit
* | e1f425a my local
|/
The default merges, producing the merge commit and the fork in the graph.
--rebase replays your commit on top instead, giving a straight line.
Look at the hash in the rebase column: e1f425a became fb288d3. Rebasing does
not move your commit, it makes a new one with the same changes. That is fine for
commits only you have, and the usual warning applies once they are shared.
Whichever you prefer, set it explicitly so it does not depend on the machine:
$ git config --global pull.rebase true # or false
Recent git versions warn when you pull into diverged history without having chosen, which is worth doing something about rather than ignoring.
fetch cannot leave you halfway
with an uncommitted edit:
fetch: ok, origin/main now a087a00
pull : error: Your local changes ... Aborting
fetch only writes to .git, so it works regardless of the state of your
working tree. pull has to merge, and a merge can refuse — or, worse, stop
partway through with conflict markers in your files.
This is why “fetch often, pull deliberately” is a reasonable habit. git fetch
is one of the few git commands that cannot put your repository into a state you
have to get out of.
About Netcup (advertisement)
The German host Netcup offers, among other things, affordable and powerful web hosting packages, KVM-based root servers and dedicated servers. With our voucher codes you can save even more (6€ off your first order, 30% off all KVM-based root servers, ...).