44

Lets say we have two branches (B and C) that have diverged from a common ancestor A. Will merging from B to C produce the same result as merging from C to B?

  A
  |
 / \
B   C

To clarify- I'm assuming that any manual merge conflict resolutions will occur in both directions. But will any automatic merges that occur result in the same code being chosen? This is what I'm assuming, since the commit dates are identical in both directions.

To further clarify - I know that the actual merging results in "mirror images" of each other based on the direction. I'm just asking about the automatically resolved conflicts.

Eyal
  • 3,412
  • 1
  • 44
  • 60
  • On a related note, you may find this now-three-year-old thread from the Git mailing list relevant, concerning how the way Git records merges is sensitive to the "direction" of the merge: http://thread.gmane.org/gmane.comp.version-control.git/127361 – seh Aug 30 '12 at 13:56
  • Does anyone know of a cached version of the link provided by @seh? The page seems to be down/gone. – tomosius Mar 29 '18 at 05:18
  • Ouch. I did some searching this evening, and still can't find a viable link. – seh Mar 30 '18 at 00:46
  • @seh I _think_ the missing discussion is this one? https://marc.info/?t=123326808700001&r=1&w=2 – MikeBeaton Apr 01 '22 at 10:26
  • That is a good thread, including some wonderful ASCII art, but I don't think it's the same one I mentioned—almost ten years ago. – seh Apr 01 '22 at 23:13

4 Answers4

32

The answer is yes for default merges. A three-way merge finds a common ancestor and then applies the differences from both sides, an operation that isn't order dependent. The topic of merge-ordering and commutativity generated a fascinating discussion on the git list (if you're into that kind of thing, that is). Note B into C and C into B should be symmetric, but the same cannot necessarily be said for (B into C) into A versus B into (C into A).

[Editing note, April 2020: If you add options like -X ours or -X theirs, the answer becomes "no", and see twalberg's answer and the others for additional caveats.]


To elaborate a bit more, based on Vince's comment below and seh's comment on the question, there will be two noticeable differences between B into C and C into B, neither of which affect the automatic merge resolution referenced in the question.

First, history will be different. The merge commit's parents will change depending on the merge order. For these examples, I'm going to use "first_branch" and "second_branch", so I can reserve letters to represent commits.

git checkout first_branch && git merge second_branch

E <- merge commit
|\
| D <- second_branch's tip
| |
| C <- another commit on second_branch 
| |
| B <- and another
|/
A <- first_branch's tip before the merge

In this case, the "first parent" of E, E^1, is first_branch's tip before the merge. second_branch is the "second parent" of the merge commit, aka E^2. Now consider the reverse:

git checkout second_branch && git merge first_branch

E <- merge commit
|\
| D <- first_branch's tip
| |
| C <- another commit on first_branch 
| |
| B <- and another
|/
A <- second_branch's tip before the merge

The parents are reversed. E^1 is the tip of second_branch before the merge. E^2 is the tip of first_branch.

Second, the display order of conflicts will reverse. In the first case, a conflict might look like this:

<<<<<<< HEAD
This line was added from the first_branch branch.
=======
This line was added from the second_branch branch.
>>>>>>> second_branch

In the second case, the same conflict would look like this:

<<<<<<< HEAD
This line was added from the second_branch branch.
=======
This line was added from the first_branch branch.
>>>>>>> first_branch

Neither of these differences affect automatic merge resolution, but they do appear when you reverse three-way merge order.

torek
  • 448,244
  • 59
  • 642
  • 775
Christopher
  • 42,720
  • 11
  • 81
  • 99
  • Would you mind providing a short example, if you tested it. I mean I am curious, if you just merge without providing any merge strategy/option but forcing automatic merge (if possible), what if there is a conflict on a line? will you have : `<<<<<<< yours:sample.txt Conflict resolution is hard; let's go shopping. ======= Git makes conflict resolution easy. >>>>>>> theirs:sample.txt`? or will you have one of them chosen, and which one? – Vince Aug 30 '12 at 14:06
  • @Vince The order matters for history and for the way those conflicts are presented, but the automatic merge resolution results will be the same. I edited in more details and a few examples. – Christopher Aug 30 '12 at 14:27
  • The post by Hamano in the discussion linked to in this answer is a must read http://thread.gmane.org/gmane.comp.version-control.git/107737/focus=107895 - not sure it provides an answer to the question though – Mr_and_Mrs_D May 23 '15 at 16:54
  • @Mr_and_Mrs_D Dead link :( – Tobias Kienzler Feb 27 '17 at 09:51
  • So git-merge is commutative (up to history metadata and merge conflict resolution). Why is it not associative? – Jasha May 31 '18 at 06:03
5

It depends on what you mean by the "same result". From a content perspective, assuming that there are either no conflicts, or all existing conflicts are meticulously resolved in exactly the same way, the contents of the resulting new merge commit should be the same.

However, from a history topology standpoint, the two are very different. If you are on branch B and merge in C, the HEAD of B moves to point to the merge commit, but C stays where it is. Conversely, if you are on C and merge in B, C's HEAD moves, while B's stays where it is. So the final topology is very different, which has implications for future development on either branch, even though the content of the new commit is identical in either case.

twalberg
  • 59,951
  • 11
  • 89
  • 84
  • Another difference in the topology, depending on which merge you did, is given in my edit in my answer below (I don't think this is already covered by the correct and useful differences you've mentioned). – MikeBeaton Apr 01 '22 at 10:06
1

The content of the files after the merge is 'symmetric' (the same, whichever merge you do), but if you use GitHub or Bitbucket or your favourite local Git viewer to view the changes made at the merge, you will see that the file changes shown in the merge commit are different depending on which merge you did (in addition to the other differences mentioned above, and in my edit below):

git checkout b
git merge c

The file changes shown in the merge will be the changes which were made on c since b and c diverged.

git checkout c
git merge b

The file changes shown in the merge will be the changes which were made on b since b and c diverged.


EDIT:

Another difference is that if you later do git reset [--hard] HEAD~{n} to roll back by a number of commits, and this goes back past the merge point, then the branch it goes back down is different depending on which merge you did, and is always the branch you merged 'into' (the one checked out, in the examples above).

MikeBeaton
  • 3,314
  • 4
  • 36
  • 45
0

no, I think it won't be symmetric. First you can set the merge strategy option, particularly in your case the theirs or ours that determines if B or C will be chosen.

In automatic merges, I think for example the remote branch has priority over your changes if you are merging into yours so it means calling git merge C from B will result in C changes being chosen. I am not 100% sure though, so you can try it your self and let us know.

Vince
  • 1,570
  • 3
  • 27
  • 48