Let's say I am on a different branch than
git pull origin <remote-branch>:<local-branch>
git pull with a refspec will not affect the merging part of the pull command. As you maybe know,
git pull is essentially just a combination of
git fetch and
git merge; first, it will fetch the newest changes from the remote and update the remote-tracking branch, and then it will merge that remote-tracking branch into the current branch.
Now, as I said, the refspec does not affect the merging part, but it only affects the fetching inside
git pull. Now to understand what this eventually means, you first have to understand what a refspec is.
A refspec is basically just a configuration which remote branches map to which remote-tracking branch. The remote branches are here the branches that actually exist on the remote, and the remote-tracking branches are the branches that are created to track the state of the remote branches; for a remote called “origin”, its remote-tracking branches all start with
If you don’t specify a refspec explicitely, it is taken from the configuration file. The default form usually looks like this:
This tells Git to fetch the remote branches located at
refs/heads/* and map them to remote-tracking branches located at
refs/remotes/origin/*. So for a remote branch
refs/heads/master will map to
refs/remotes/origin/master. The leading
+ also tells Git to overwrite the remote-tracking branch regardless of whether the changes could be fast-forwarded or not: After all, you usually want your remote-tracking branches to match exactly the state on the remote, so if the history is rewritten there (which should be avoided) or branches are renamed, you would want the remote-tracking branches to still respect that.
Now, when you specify the refspec (using
git fetch or
git pull), the default mapping is overridden. Instead, your mapping is used. For example, when you use
git fetch origin master:foo, then a local branch
foo is fast-forwarded (if possible) to point to the remote branch
master. So this is actually a fine way to update a local branch, without having to check it out: If you leave out the leading
+, then updating the local ref (branch) will fail if it’s not a fast-forward merge, so you’re also safe against conflicts.
But coming back to
git pull—what happened when you ran the command? As I said, a pull is just a fetch and a merge, so your
git pull command first did this:
git fetch origin <remote-branch>:<local-branch>
So the remote branch is fetched from the remote, and the local branch is updated—if it’s a fast-forward merge. This already does exactly what you wanted: Update
But then, the merge part of
git pull happens; and Git usually runs
git merge FETCH_HEAD for this purpose.
FETCH_HEAD is a reference to the last fetched branches. In this case, it points at
<local-branch>. So after fetching into
<local-branch>, the command that is being executed is
git merge <local-branch>. And running
git merge will merge into the current branch.
So when you’re on
<different-branch> and run
git pull origin <remote-branch>:<local-branch> then you will correctly update
<local-branch> to match the remote branch, but you will then also merge those changes into the current branch,
<different-branch>. That’s why you see the changes of that branch in the log of the current branch; they were simply merged.
If you want to avoid that, as per my explanations above, just use
git fetch with the refspec. It will already update the local branch correctly (if it can) without affecting the current branch.