How Do I 'git fetch' and 'git merge' from a Remote Tracking Branch (like 'git pull')
You don't fetch a branch, you fetch an entire remote:
git fetch origin
git merge origin/an-other-branch
Selecting just one branch: fetch
/merge
vs. pull
People often advise you to separate "fetching" from "merging". They say instead of this:
git pull remoteR branchB
do this:
git fetch remoteR
git merge remoteR branchB
What they don't mention is that such a fetch command will actually fetch all branches from the remote repo, which is not what that pull command does. If you have thousands of branches in the remote repo, but you do not want to see all of them, you can run this obscure command:
git fetch remoteR refs/heads/branchB:refs/remotes/remoteR/branchB
git branch -a # to verify
git branch -t branchB remoteR/branchB
Of course, that's ridiculously hard to remember, so if you really want to avoid fetching all branches, it is better to alter your .git/config
as described in ProGit.
Huh?
The best explanation of all this is in Chapter 9-5 of ProGit, Git Internals - The Refspec (or via github). That is amazingly hard to find via Google.
First, we need to clear up some terminology. For remote-branch-tracking, there are typically 3 different branches to be aware of:
- The branch on the remote repo:
refs/heads/branchB
inside the other repo - Your remote-tracking branch:
refs/remotes/remoteR/branchB
in your repo - Your own branch:
refs/heads/branchB
inside your repo
Remote-tracking branches (in refs/remotes
) are read-only. You do not modify those directly. You modify your own branch, and then you push to the corresponding branch at the remote repo. The result is not reflected in your refs/remotes
until after an appropriate pull or fetch. That distinction was difficult for me to understand from the git man-pages, mainly because the local branch (refs/heads/branchB
) is said to "track" the remote-tracking branch when .git/config
defines branch.branchB.remote = remoteR
.
Think of 'refs' as C++ pointers. Physically, they are files containing SHA-digests, but basically they are just pointers into the commit tree. git fetch
will add many nodes to your commit-tree, but how git decides what pointers to move is a bit complicated.
As mentioned in another answer, neither
git pull remoteR branchB
nor
git fetch remoteR branchB
would move refs/remotes/branches/branchB
, and the latter certainly cannot move refs/heads/branchB
. However, both move FETCH_HEAD
. (You can cat
any of these files inside .git/
to see when they change.) And git merge
will refer to FETCH_HEAD
, while setting MERGE_ORIG
, etc.
Are you sure you are on the local an-other-branch
when you merge?
git fetch origin an-other-branch
git checkout an-other-branch
git merge origin/an-other-branch
The other explanation:
all the changes from the branch you’re trying to merge have already been merged to the branch you’re currently on.
More specifically it means that the branch you’re trying to merge is a parent of your current branchif you're ahead of the remote repo by one commit, it's the remote repo that's out of date, not you.
But in your case, if git pull
works, that just means you are not on the right branch.