Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are merges in Git symmetric?

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.

like image 970
Eyal Avatar asked Aug 30 '12 08:08

Eyal


People also ask

How do merges work in Git?

How does git merge work? Git merge combines several sequences of commits into a single history. In most cases, that means merging two branches—most often a feature branch and the master branch. In this case, Git will take the commits from the branch tips and try to find a common base commit between them.

Does merge change both branches?

No, merging does only affect one branch.

What happens when two branches are merged in Git?

Merging Branches. Once you've completed work on your branch, it is time to merge it into the main branch. Merging takes your branch changes and implements them into the main branch. Depending on the commit history, Git performs merges two ways: fast-forward and three-way merge.


2 Answers

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.

like image 96
Christopher Avatar answered Sep 23 '22 12:09

Christopher


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.

like image 38
twalberg Avatar answered Sep 25 '22 12:09

twalberg