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 pullreallygit 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 fetchis run without specifying what branches and/or tags to fetch on the command line, e.g.git fetch originorgit fetch,remote.<repository>.fetchvalues 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