问题
Say there is a remote branch br1
checkout on the remote repo, and the master
branch on a local repo.
Command 1: If I do a "
git pull origin br1:br1
" it pulls remotebr1
into localbr1
, and shows:9188a5d..97d4825 br1 -> br1 9188a5d..97d4825 br1 -> origin/br1
command 2: If I do just a "
git pull
", it will pull remotebr1
into localmaster
, but it shows only the following:9188a5d..97d4825 br1 -> origin/br1
I'm expecting it also shows something like "br1 -> master
". Why it does not show that?
Does "br1 -> br1
" mean pulling remote br1
into local br1
?
What does that "br1 -> origin/br1
" mean?
Update: With help from VonC, I figured out the following:
git pull
updates all the tracking branches.br1 -> origin/br1
meansbr1
on the remote is pulled into local tracking branchorigin/br1
.git pull origin br1:br1
pulls remotebr1
into localbr1
and intoorigin/br1
. Then the messages after that mean the same change set is also pulled into the current checked-out branch (the message isUpdating ...
, it does not showbr1 -> master
):$ git pull origin br1:br1 beb48a4..b344dd1 br1 -> br1 beb48a4..b344dd1 br1 -> origin/br1 Updating cca5a9b..b344dd1 Fast-forward file2 | 0 file3 | 0 4 files changed, 0 insertions(+), 0 deletions(-)
Previously I thought
git pull
pulls into the local master. That is not the case. It is thatgit pull origin br1:br1
does it.
Update 2: With explanations by torek, the specific problem is that the command git pull origin br1:br1
pulls remote br1
into FETCH_HEAD
after a sequence of other actions and subsequently merges the FETCH_HEAD
onto the current branch.
回答1:
Warning: long. TL;DR version: you are looking at git fetch
output and git fetch
is not affecting your master
at all, it's the git merge
part of your git pull
that affects your master
. However, your git fetch
is updating a remote-tracking branch origin/br1
and in one case updating or even creating a local branch br1
.
git pull
is a convenience script
Always remember that git pull
is just a convenience script that runs two other git commands for you: first, git pull
passes your arguments on to git fetch
. Once that finishes, git pull
runs git merge
(or, if instructed, git rebase
), but all of the quoted action in your original question is occurring purely in git fetch
. (A bit in the "update" section is from git merge
, which I'll get to later.)
If you do not provide a remote argument to git pull
, the pull
script extracts one from your current branch's configuration. In this case, the one it extracts is clearly origin
. So If you run git pull
without specifying origin
, you are, in effect, running git pull origin
.
If you do not provide a refspec argument to git pull
, the pull
script extracts a very simple one from your current branch's configuration—in this case, whatever you see from git config --get branch.master.merge
, which apparently is br1
. So this means that if you run git pull origin
, you are in effect running git pull origin br1
.1
Again, all of this is then just passed on to git fetch
, so whether you run git pull
, git pull origin
, or git pull origin br1
, all of those just wind up invoking:
git fetch origin br1
(which you can also do manually, and you'll see the above).
We'll get to git fetch origin br1:br1
later, below.
Background on possible misconceptions
Let's take a brief look at your setup statement again:
Say there is a remote branch
br1
checkout on the remote repo, and themaster
branch on a local repo.
What branch, if any, is currently checked-out on the remote is mostly irrelevant for fetch
. The first (or first-enough) thing fetch
does is to connect to the remote and ask it for a list of all references and their corresponding SHA-1s (you can see what git fetch
can see by running git ls-remote
). The remote's HEAD
is included in that list, and this allows you to direct your fetch
to use it, but if you don't, your fetch
just ignores it (the remote's HEAD
is mostly only used for controlling the default initial branch on an initial git clone
).
The current branch in your local repo is important, though, for two reasons:
- if you don't supply extra arguments to
git pull
, it finds them based on your current branch; and - after the
fetch
succeeds,git pull
runs eithergit merge
orgit rebase
, which uses your current branch.
Again, your current branch is master
so pull
will use branch.master.remote
and branch.master.merge
as the default remote and refspec arguments.2 This is how we can deduce, from the original output, that these are origin
and br1
respectively.
On git fetch
Returning to git fetch
, what it does is to confer with the remote git server a bit to find out what references (branches and tags, mostly) are available and what their corresponding SHA-1 values are. Once it has that information, it then looks at which references you've asked it to bring over. If you listed a specific reference like br1
, that's the one reference it will bring over.
Along with each reference, of course, it has to bring any new objects (the commit itself, and its associated trees and files, plus any parent commits and their trees-and-files as needed) so that you get all the history from that particular point backwards. Whatever history you already have, of course, it can skip.3
As VonC already noted, git's behavior on git fetch remote refspec
has changed in git 1.8.4 and later. It used to be the case that if you ran git fetch remote refspec
, your refspec overrode the rules in your git configuration entry for that remote, but now it simply selects from them. By default, the rule-set for the remote named origin
is +refs/heads/*:refs/remotes/origin/*
, so your br1
refspec selects an item from this rule-set.
Let's pause to see what happens if you run git fetch
with only three arguments, like this:
$ git fetch origin
Here you are instructing your local git to connect to the remote, find out what it has, and bring over all branches. The way (and reason) it does that is just as outlined above: it connects, gets a list, and then consults the output of git config --get-all remote.origin.fetch
.4 This is a list of "refspecs", one per git config --get-all
line.
Since the standard line (one single line) for remote.origin.fetch
is +refs/heads/*:refs/remotes/origin/*
, your local git will take every reference-name that matches refs/heads/*
. That is, it will take all branches on origin
, because branches are simply "references whose names start with refs/heads/
". What it does with those branches is determined by the right-hand side of this refspec: it replaces refs/heads/
with refs/remotes/origin/
.
The result is a "remote-tracking branch". If the remote has a branch master
, your local git translates this to origin/master
. If the remote has a br1
, your local git translates that to origin/br1
. For each branch on the remote, you get a (local) remote-tracking branch whose name starts with origin/
.5
Returning to our case of git fetch origin br1
, we can now see what happens: our local git brings over br1
, which turns out to be a branch so that its full name is refs/heads/br1
. Because of that, it matches the standard remote.origin.fetch
line and refs/heads/br1
is translated to refs/remotes/origin/br1
, which causes git to print out origin/br1
:
9188a5d..97d4825 br1 -> origin/br1
The name br1
on the left is the short name of the reference on the remote, and the name origin/br1
on the right is the short name of the reference that git fetch
has updated.
In the past you would instead see something like this—and you still may see it:
* branch name -> FETCH_HEAD
This indicates that git fetch
found a branch named name
(i.e., a reference of the form refs/heads/name
) on the remote and brought it over to your local repo and put it in FETCH_HEAD
. What is FETCH_HEAD
? It's a special file that exists pretty much just for the git pull
script. (It works a lot like a reference, but it has a special format and may contains multiple SHA-1s.)
Now we're (finally) ready to tackle the br1:br1
case. Here, you're telling your local git fetch
to bring over reference br1
. It does the usual—call up the remote, discover that br1
is really refs/heads/br1
, and bring over the reference and any needed objects—but this time, in addition to consulting the remote.origin.fetch
line, it writes the new SHA-1 into the reference you specified.
In this case, you specified br1
with no qualifications: not refs/heads/br1
, not refs/remotes/origin/br1
, just br1
. In this case, git sees that it's a refs/heads/
reference on the remote, meaning it's a branch; so git adds refs/heads/
on your end as well, and creates or updates your own refs/heads/br1
.
In other words, this creates or updates your local branch br1
.
In addition, git still applies the remote.origin.fetch
line, which is still +refs/heads/*:refs/remotes/origin/*
, so it still updates your remote-tracking branch origin/br1
(full name refs/remotes/origin/br1
). That's why you got the output you got from Command 1.
On git merge
What about FETCH_HEAD
? Well, that's where the rest of git pull
comes back in: after doing the git fetch
step, the pull
script runs either git merge
or git rebase
. What it merges (or rebases-on-to) is whatever git fetch
left behind in the FETCH_HEAD
file (with some special casing and other caveats that I won't go into here).
When your current branch is master
but you instruct git pull
to pull origin br1
, it's the git merge
step that brings master
up to date with br1
. More precisely, the merge gets you up to date with your copy of origin/br1
as of the time the git fetch
finished—it's possible that just after your git fetch
finished, someone else did a git push
that updated br1
on your remote.
The merge is a "fast-forward" merge if possible, but again I won't go into any more details on that here. I'll just note that it was possible, so it was done; that's the Fast-forward
line in the update.
In any case, the merge brought in to your current branch (master
) the changes since the merge-base of your current branch and your target commit (the raw SHA-1 that git fetch
left in the FETCH_HEAD
file, which is also the new SHA-1 of origin/br1
, and in one case, the new SHA-1 of new-or-updated local branch br1
).
In pre-1.8.4 versions of git, the origin/br1
remote-tracking branch is not updated. Everything still works out of the FETCH_HEAD
file though, and it is, if anything, even more confusing than in newer gits, where we can say that you're now up to date with origin/br1
without having to be very exacting and picky about "br1
as it was on the remote at the time you ran git fetch
".
What's that plus sign?
Sharp-eyed readers will have noted the +
in +refs/heads/*:refs/remotes/origin/*
. This +
symbol means "forced update". Normally, when updating a branch reference—any reference starting with refs/heads/
—git won't allow the update unless it's a "fast-forward" label update. Setting the force flag in a refspec allows that particular update. Using --force
on the command line also allows that update, and all other reference updates as well. In other words, the plus sign is simply a more-targeted (single refspec) version of --force
.
1This is an overstatement: sometimes it uses a three-argument git fetch
.
2Always true for the remote bit but the refspec bit may be empty, with the pull
script figuring out which refspec to apply later, after git fetch
finishes.
3By default, the fetch
operation will also bring over any tag-name references that match any commit-IDs that it brings over. If you run git fetch
yourself, you can change the way fetch
handles these, but if you just let git pull
run git fetch
you will get this default behavior. Note that it's your local git that makes these decisions: the remote git simply displays everything to your local git, and then your git decides whether to add tags to your repository.
4Technically git fetch
just invokes the C code that does this, rather than actually running git config --get-all
. In any case, if there are multiple configuration entries for remote.origin.fetch
, git fetch origin
really does apply all of them. The way it does this is a bit complicated though, and I will skip the gory details here.
5Remote-tracking branches are really just references whose name starts with refs/remotes/
, just as local branches are references whose name starts with refs/heads/
. This is a general thing in git: your tags are references whose name starts with refs/tags
. The git stash
script uses a single special reference, refs/stash
. Git's "notes" are stored under refs/notes/
, and you can invent your own references: just pick a different starting string, and hope that nobody else picks the same one in the future for a new git feature. :-)
回答2:
Any line with origin/xxxx
means the git fetch
part of a git pull (which is git fetch + git merge) has updated a remote tracking branch.
that is so since git 1.8.4 (before it only updated FETCH_HEAD).
If I do just a "git pull", it will pull remote br1 into local master
That would depend on git config branch.b1.merge
, which instruct the git merge part of the git pull
where to merge.
By doing a git pull b1:b1
, you are overriding that config and instructing the merge to take place in the local b1
branch.
See also the result of git branch -avvv to see what local branch is tracking what remote branch.
I'm expecting it also shows something like "br1 -> master". Why it does not show that?
Maybe master
was already at 97d4825
.
来源:https://stackoverflow.com/questions/28337390/git-pull-command-output-message-meaning-into-which-branch