Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git merge diff3 style need explanation

I've merged 2 branches and conflicts appeared, I would need some hints where it starts where it ends, etc. I've replaced the code with some faked data to make it easier to read and talk about.

<<<<<<< HEAD     aaaaaa ||||||| merged common ancestors <<<<<<< Temporary merge branch 1     bbbbbb =======     cccccc >>>>>>> mybranch     dddddd <<<<<<< HEAD     eeeeee ||||||| merged common ancestors     ffffff ||||||| merged common ancestors     gggggg ======= >>>>>>> Temporary merge branch 2 =======     hhhhhh >>>>>>> mybranch 
like image 865
mingle Avatar asked Jun 07 '13 18:06

mingle


People also ask

How does git merge handle whitespace differences between versions?

If their version only introduces whitespace changes to a line, our version is used; If our version introduces whitespace changes but their version includes a substantial change, their version is used; Otherwise, the merge proceeds in the usual way.

What merged common ancestors?

merged common ancestors: diff3 outputs an additional "middle" section showing the lines as they were in the merge base. This is the starting point for both branches. Criss-cross merge: A merge history where two branches merge into each other in ways that one could not have been a fast-forward merge.

Why do we need git merge?

Merging is Git's way of putting a forked history back together again. The git merge command lets you take the independent lines of development created by git branch and integrate them into a single branch.

How does git decide to merge?

Git has an internal merge system that is independent of difftool . So Git decides when a change causes a conflict on its own, not by using whatever external diff or merge tools you're using (which probably use their own conflict detection and resolution strategies).


2 Answers

What you're seeing in this example (with Temporary merge branch markers) is the result of diff3 with a criss-cross merge conflict. I'll explain this with a sequence of definitions.

Definitions

  • merge base: The commit where the two merging branches most recently diverged from. When a merge conflict occurs, different changes were made to the same lines in both branches. The merge base contains what those lines were before either branch changed them.
  • merged common ancestors: diff3 outputs an additional "middle" section showing the lines as they were in the merge base. This is the starting point for both branches.
  • Criss-cross merge: A merge history where two branches merge into each other in ways that one could not have been a fast-forward merge. I give an example below. In a criss-cross merge situation, there are multiple merge bases.
  • Temporary merge branch: When there are multiple merge bases, diff3 attempts to merge them together (using temporary merge branches) to form a single common ancestor to show in diff3's middle section. This works seamlessly when there are no conflicts, but when there are conflicts, you see the temporary merge branch's conflict markers inside the middle merged common ancestors section.

Example criss-cross merge conflict scenario

A criss-cross merge occurs whenever two branches merge into each other at different points in time.

m3 *    |\    | \    |  * B1    |  | m2 *  * B0    |\/|    |/\| m1 *  * A    | /    |/ m0 * 

Consider this sequence of events:

  • m0 exists as origin/master
  • I create a feature branch feature-A with one commit A
  • m1 gets committed to master by someone else
  • I start a new feature branch feature-B that builds on A
  • I merge origin/master (m1) into feature-B. It conflicts, and I resolve it. The merge commit is B0.
  • I implement feature-B and commit the work as B1.
  • feature-A is ready to ship, so someone merges it into master. It conflicts. They resolve it, but their resolution differs from the resolution in B0. The merge commit is m2.
  • feature-B is ready to ship, so someone merges it into master. git tries to determine the merge base, but m1 and A both qualify equally as merge bases. git merges m1 and A in a temporary merge branch, which results in a conflict. We see diff3 output in the merged common ancestors section, similar to the OP's question.

Reading the output

With diff3 off, this merge conflict would look simply like this:

<<<<<<< HEAD     aaaaaa =======     hhhhhh >>>>>>> mybranch 

First, with all the extra markers, you'll want to determine what the actual conflicting lines are, so you can differentiate it from the diff3 common ancestor output.

conflict with merged common ancestor blurred

aaaaaahhhhhh, that's a little better. ;-)

In the case where two conflict resolutions are conflicting, aaaaaa and hhhhhh are the two resolutions.

Next, examine the content of the merged common ancestor.

merged common ancestor conflicts, grouped

With this particular merge history, there were more than 2 merge bases, which required multiple temporary merge branches which were then merged together. The result when there are many merge bases and conflicts can get pretty hairy and difficult to read. Some say don't bother, just turn off diff3 for these situations.

Also be aware that git internally may decide to use different merge strategies to auto-resolve conflicts, so the output can be hard to understand. Make sense out of it if you can, but know that it was not intended for human consumption. In this case, a conflict occurred when merging mybranch into Temporary merge branch 1 between bbbbbb and cccccc. Line dddddd had no conflicts between the temporary merge branches. Then a separate conflict occurred when merging Temporary merge branch 2 into HEAD, with multiple common ancestors. HEAD had resolved the conflict by merging ffffff and gggggg as eeeeee, but Temporary merge branch 2 resolved that same conflict by deleting (or moving) the line (thus no lines between ====== and Temporary merge branch 2.

How do you resolve a conflict like this? While technical analysis may be possible, your safest option is usually to go back and review the history in all the involved branches around the conflict, and manually craft a resolution based on your understanding.

Avoiding all this

These conflicts are the worst, but there are some behaviors that will help prevent them.

  1. Avoid criss-cross merges. In the example above, feature-B merged origin/master as B0. It's possible that this merge to stay up-to-date with master wasn't necessary (though sometimes it is). If origin/master was never merged into feature-B, there would have been no merge criss-cross, and m3 would have been a normal conflict with A as the only merge base.

    m3 *              m3 *    |\                |\    | \               | \    |  * B1           |  * B1    |  |              |  | m2 *  * B0   VS   m2 *  |    |\/|              |\ |    |/\|              | \| m1 *  * A         m1 *  * A    | /               | /    |/                |/ m0 *              m0 * 
  2. Be consistent with conflict resolutions. In the example, the Temporary merge base conflict only occurred because m2 and B0 had different conflict resolutions. If they had resolved the conflict identically, m3 would have been a clean merge. Realize though that this is a simple criss-cross merge that ought to have had the same resolution. Other situations may rightly have different resolutions. Things get more complicated when there are more than 2 merge bases and multiple commits between the merge points. That said, if you are knowingly inconsistent with conflict resolutions in criss-cross situations, expect headaches later.
like image 79
Edward Anderson Avatar answered Oct 04 '22 14:10

Edward Anderson


Here's an article about git's diff3 merge style. It points out that it's hard to tell whether lines are being added or deleted in this style.

I suggest you refine your question if you are looking for specific information. It's hard to tell what you're asking.

like image 40
neontapir Avatar answered Oct 04 '22 12:10

neontapir