I was practicing git in the following sandbox: https://learngitbranching.js.org/?NODEMO
I ran two sets of commands in two separate sessions. The first set of commands in order is as follows:
git clone
git checkout -b feature
git push
git fakeTeamwork main 1
git fakeTeamwork feature 1
git pull
The second set of commands in order are similar but I use git fetch
+ git merge
at the end instead:
git clone
git checkout -b feature
git push
git fakeTeamwork main 1
git fakeTeamwork feature 1
git fetch
git merge o/feature
If git pull
= git fetch
+ git merge
, why are the two outcomes different? It seems that git pull
does not update all the remote tracking branches. Is this just a flaw of the sandbox or is this actually what happens in git?
Note: The commands git clone
and git fakeTeamwork
are just commands built for the sandbox
Thank you!
It seems that git pull does not update all the remote tracking branches.
This can happen, yes. It does happen when:
git pull
runs git fetch origin master
, for instance, andgit fetch origin master
therefore only updates origin/master
.Futhermore, in Git versions predating 1.8.4, some git fetch
operations do not update any remote-tracking names at all. Here the git fetch origin master
has no effect on origin/master
.
Besides these, we have several other special cases:
git pull
is configured or told to run git rebase
, the second command it uses is git rebase
, not git merge
. The obvious substitute is thus git fetch
followed by git rebase
. Some specifics here are even-more Git version dependent, though: in particular, git pull
implemented --fork-point
mode for rebase before git rebase --fork-point
existed (the actual --fork-point
option first occurring in Git 1.9, but git pull
doing special work since some 1.6 version—I looked up the precise version once, but these days the oldest Git in use seems to be for CentOS, which includes some Git 1.7 versions in some distributions).git pull
, there is no existing branch yet. (You can trigger this case again later using orphan branches.) In this case instead of either merge or rebase, git pull
runs a specialized git checkout
.The upstream setting of a branch matters here, depending on what arguments you pass to git pull
or to the fetch and second commands. In general these mostly end up working the same way, except for the caveat you noted about some remote-tracking names sometimes not getting updated.
Is
git pull
reallygit fetch
+git merge
?
In short, yes.
However, it's worth pointing out that which remote tracking branches are updated by git fetch
(when invoked without any arguments) is determined by the remote.<repository>.fetch
configuration variable.
If you run git config remote.origin.fetch
in a real Git repo, you should see the following:
+refs/heads/*:refs/remotes/origin/*
This is called a refspec. The *
is telling Git to fetch all branches in the origin
remote (the right-hand side of the :
) and put them in your local repo (the left-hand side of the :
). If you run git pull
or git fetch
without any arguments, all new and existing remote tracking branches are going to be updated thanks to this setting.
From the documentation:
When
git fetch
is run without specifying what branches and/or tags to fetch on the command line, e.g.git fetch origin
orgit fetch
,remote.<repository>.fetch
values are used as the refspecs—they specify which refs to fetch and which local refs to update. The example above will fetch all branches that exist in theorigin
(i.e. any ref that matches the left-hand side of the value,refs/heads/*
) and update the corresponding remote-tracking branches in therefs/remotes/origin/*
hierarchy.
This behavior no longer applies once you start passing the branch name to git pull
or git fetch
, as @torek pointed out in his answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With