As in my other comment recently, I'd like to avoid the term "local-tracking branch" entirely and concern myself here only with whether a local branch has an upstream set, and if so, what that upstream is set to (which as the book you're quoting notes, is split into two parts, the "remote" and "merge" strings).
For your first question:
Generally speaking, does the merge step merge the remote tracking branch into master or the current branch?
It's always the current branch. The git pull
command (which used to be a script but was recently rewritten in C) actually runs git merge
, and git merge
always starts with the current branch (and current work-tree).
What gets merged-in is a bit trickier. Again, this is a bit you quoted; I will just move the emphasis:
... git pull
... calls git merge
to merge the retrieved branch heads into the current branch.
Once you're comfortable with "always merges into the current branch", the remaining key question here is: which branch heads were retrieved?
The answer is a little bit complicated, as it depends on the arguments you pass to git pull
. The general form is git pull remote [options] refspec [refspec ...]
, i.e., the second word is the literal string pull
, the third word (after parsing any options) is the name of the remote, and the fourth-and-further words are "refspecs".
You can specify a refspec, or multiple refspecs, in which case git fetch
uses those to bring over some specific branch head or heads, and those are what get merged. Or, you can leave them out, in which case git pull
directs git fetch
to bring over the current branch's upstream.1
This leads to a common mistake. If you have local branches A
and B
that are set to track origin/A
and origin/B
respectively, people like to enter the command git pull A B
, thinking this will update origin/A
and origin/B
—and it will!2—but then also thinking that git would then merge origin/A
into A
, and origin/B
into B
, and it won't. Instead, it brings over the two branch heads, then runs an "octopus merge" into the current branch (whatever the current branch is).
The answer to this multi-part question, then, is:
Does git pull merge the remote tracking branch always into the current branch? (My guess is yes). if not, is there an argument to git pull that specifies the target branch in the merging step? If I am correct, the refspec argument to git pull doesn't specify the target branch for merging step.
(A) No, or at least, it's not guaranteed: it merges the retrieved branch heads (which git fetch
recorded in FETCH_HEAD
; and if git fetch
retrieved extra heads, which it does sometimes, it marks those not-for-merge
to "hide" them from the merge step), which may or may not be the same as the remote-tracking branch set as the current branch's upstream. In my experience, most users are surprised when it's not the current branch's upstream; that's usually not what they wanted.
(B) Yes: the "refspecs" you specify (if any) determine which branch heads are retrieved. Fetch refspecs are subtly different from push refspecs and I won't go into a lot of detail here (see this answer for details), but the short version is that if you leave out the colon :
, these are the heads deposited into FETCH_HEAD
for merging. The pull
code supplies a default refspec if needed, so that there's something in FETCH_HEAD
.
The answer to this question is also a bit complicated, because the question has two assumptions built in that may be wrong:
Why is the merge a "fast-forward merge"?
First, it isn't necessarily a fast-forward merge.
Second, "fast-forward merge" is something of a misnomer, or at least, a short-cut name that obscures a deeper truth. "Fast-forwarding" is really a property of a label move rather than of a merge. Git calls a merge a "fast-forward" when no actual merge is required and the simple label move can be done instead.
Remember that in git, the word "branch" has at least two meanings: there's the branch name, like master
or feature
or bug2.71828
or whatever, and then there's the underlying commit-graph data structure. The data structures are permanent but the names are ephemeral and can be changed.3 When you ask git to merge the branch named X
into your current branch, it first resolves the name X
to a commit ID. It then checks whether the current HEAD
commit (the tip of your current branch) is an ancestor of the target commit ID. If so, no actual merge is required.4
In the "no actual merge required" git will normally replace the merge operation with a simple label-move: if HEAD
is a symbolic reference to a branch name (i.e., if you're "on a branch" in git status
terms), the branch name—the label—is simply "moved forward" to point to the target commit. (If you're in "detached HEAD" mode git does the same thing but writes the new ID into HEAD
itself, rather than into the current branch's file.)
The --no-ff
flag, if you give it, forces git merge
to make an actual merge commit even if fast-forwarding is possible. (In the same-but-opposite fashion, --ff-only
forces git not to make a merge, but if a true merge would be required, the only way to not make one is to fail, so --ff-only
will fail in this case, while --no-ff
succeeds in both "merge required" and "no merge required" cases.)
This answer is already long enough (or too long :-) ) so all I will say about adding --rebase
is that the fetch
step works the same, but the pull
code then uses git rebase
(with --onto
, and with recent versions of git, some extra complications using "fork points") to rebase onto the fetched head (and must error out if you fetch multiple heads, since you can't rebase onto more than one head).
1There's a special exception for the case where the current branch's upstream has a literal dot .
as its "remote" name. In this case, the "merge" setting refers to another local branch, rather than a remote-tracking branch, and git pull
skips the git fetch
step since there's no need to fetch from yourself.
2This assumes you have git version 1.8.4 or newer. In older versions of git, the git fetch
step brings over the branch heads, but fails to update origin/A
and origin/B
, for reasons that were intentional but turned out bad (hence the change in 1.8.4).
3As far as I know, git is unique in this respect. Other VCSes, including Mercurial, don't implement branches this way. Branches can still be renamed, but the names are much more deeply embedded and cannot be removed entirely, the way they can be in git.
4Alternatively, we can say that git first computes the merge-base, and if the merge-base is the current commit, no actual merging is required.