Reputation: 80
I'm just curious if this is how git works. If git pull
or git merge
have a difference depending on what branch I'm on.
So basically, is
On branch A: git pull origin B
the same as
On branch B: git pull origin A
Upvotes: 0
Views: 59
Reputation: 487775
phd's answer is correct, but I would go further: They can, in some cases, be extremely different. It really depends on what the names A
and B
identify in the Git at the URL over at origin
. If these names are not related to your names A
and B
, the results can be pretty surprising.
As phd said, git pull
means run git fetch
, then run a second Git command, typically git merge
(but you can choose which command to run second). The fetch step uses the arguments you gave—in this case, B
or A
respectively—to limit what gets fetched. But: what exactly does get fetched?
Remember that Git is really all about commits. You have some set of commits in your repository. Each of those commits has a unique hash ID. Their Git, too, has some set of commits in their repository. Each of their commits has a unique hash ID. Your Git and their Git—and in fact, every Git in the universe—agree on these hash IDs. So if you and they both have one specific commit, you both use the same hash ID for that one commit. That's how your Git and their Git know which commits are which! Your Git can tell if their commits are new to you, or not, by inspecting the hash IDs.
Where do branch names come into this picture? The answer is: branch names help any Git find commits. A branch name like A
or B
tells a Git: this commit—the hash ID of which is stored under the branch name—is the last commit in the branch. It's the commits themselves that form the branch. The name just lets Git find the last one. The hash IDs themselves look random. We (humans) need branch names because there's no way we're going to remember any of the hash IDs, and Git needs them to know where to start: at the end of the branch.
But the names are not shared. Their Git has their branch names, and your Git has your branch names, and there's no need for them to match up in any way. It's pretty convenient for you if you make yours match up with theirs, and Git can help you make that happen—but it's not at all guaranteed.
To help you keep track of this sort of stuff, it's helpful to draw parts of the commit graph. You can use a graphical viewer (gitk
, the Git GUI, and many others); some are good and some are not. Or, you can use the command-line git log --graph
option. It's particularly useful with four options combined:
git log --all --decorate --graph --oneline
which tries to draw a useful summary of all commits on all branches and other references (--all
), with the interconnecting lines from child commits to their parents (--graph
) while using a one-line format (--oneline
) and labeling each commit that has a branch or tag name pointing to it with those branch and/or tag names (--decorate
).
We can also do this sort of graph-drawing by hand, and that's often pretty useful. Suppose that you have, in your repository, something that looks like this:
...--F--G------H <-- branch-A
\
I--J <-- branch-B
The single uppercase letters here stand in for actual commit hash IDs (which are long and ugly and random-looking); git log --all --decorate --oneline --graph
will print actual hash IDs, but abbreviated, and will try to draw this vertically instead:
* b9124f1 (Branch-A) subject line from commit H
| * a123456 (Branch-B) subject line from commit J
| * 02ca132 subject line from commit I
|/
* e310f45 subject line from commit G
* 7720dd4 subject line from commit F
for instance.
Now, suppose the name branch-A
on the other Git, the one your Git calls origin
, identifies the same commit as your own branch-A
. Suppose further that the other Git's branch-B
also identifies the same commit as your own branch-B
. Then:
git fetch origin
has your Git call up their Git, find all their branches, copy any new commits they have that you don't into your own Git, and then create or update a series of origin/*
names by taking their names and renaming them. So after this git fetch
operation, we can draw your Git's contents this way:
...--F--G------H <-- branch-A, origin/branch-A
\
I--J <-- branch-B, origin/branch-B
That is, you haven't gained any new commits (you both had the same set of commits) but your Git now remembers that their branch-A
identifies commit H
, just like yours, and their branch-B
identifies commit J
, just like yours.
But what if that's not what their branch names identify? What if their branch-A
identifies commit J
, and their branch-B
identifies commit F
? Then you'll have:
...--F <-- origin/branch-B
\
G------H <-- branch-A
\
I--J <-- branch-B, origin/branch-A
Or, they might have new commits that you don't. Maybe their branch-A
points to a new commit whose parent is H
; let's call that commit K
:
K <-- origin/branch-A
/
...--F--G------H <-- branch-A
\
I--J <-- branch-B, origin/branch-B
These are all possibilities. Without actually inspecting your repository after using git fetch
to get any new commits from their repository and to update your various origin/*
names, we can't really know what will happen.
But if, in this state of ignorance,1 we go ahead and run git pull
, git pull
will first run git fetch
and obtain new commits (if there are any) and then run git merge
. That git merge
will try to merge the new commits, if any, or the existing commits, if we already had them, to whatever branch we have checked out right now. Essentially, we'll ask the other Git: What commit hash ID does your branch-A
or branch-B
identify? We'll get any new commits we need, and then we'll git merge
the commit their branch-A
or branch-B
identified. What exactly will that do? Unless we know what their branch-A
or branch-B
identifies, before we ask them what it identifies, there's no way to know what that will do.
In some (well-controlled) situations, you can be pretty sure what will happen: you know who's allowed to do what to the Git repository over at origin
, so you can predict, with at least some accuracy anyway, what their branch-A
or branch-B
will mean. In that case, git pull
isn't all that unsafe. I still prefer to run git fetch
separately myself, but you may well be able to use git pull
. Just remember that git pull
means run git fetch
, then run a second Git command on whatever fetch brought in. If that second command is git merge
, know what git merge
does. If that second command is git rebase
, know what git rebase
does.
1Ignorance here simply means not knowing. It's impossible, in general, to know in advance of the git fetch
what exactly the git fetch
will do. So any time you use git pull
you're taking chances! I prefer to run git fetch
first, then see what the fetch did, and only then decide whether it's appropriate to run git merge
.
Upvotes: 1
Reputation: 94407
They're different. The first one means
git checkout A
git fetch origin B # to FETCH_HEAD
git merge FETCH_HEAD # to branch A
while the second is equivalent to
git checkout B
git fetch origin A
git merge FETCH_HEAD # to branch B
The major difference is which branch is merged to which.
Upvotes: 2