Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a common ancestor needed in a 3 way merge commit?

Tags:

git

I'm reading this:

In this case, Git does a simple three-way merge, using the two snapshots pointed to by the branch tips and the common ancestor of the two.

3-way

Three snapshots used in a typical merge. Figure 3-16. Three snapshots used in a typical merge Instead of just moving the branch pointer forward, Git creates a new snapshot that results from this three-way merge and automatically creates a new commit that points to it. This is referred to as a merge commit, and is special in that it has more than one parent.

The two tips make sense... but why do you need the common ancestor?

like image 201
Jwan622 Avatar asked Oct 18 '25 14:10

Jwan622


2 Answers

Git needs to know what changed in each branch, so let us say that master change file A, and iss53 changed file B. Without finding the common ancestor, Git would only know that both files A and B are different in the tips, but not which version of A and B to pick.

By comparing the tips to the common ancestor, Git can reliably see that A has not changed for iss53, and therefore uses master's version of A, and vice versa for B.

Of course thing get more complicated when the same file is modified by both branches, but this should clarify things.

like image 109
Joseph K. Strauss Avatar answered Oct 20 '25 05:10

Joseph K. Strauss


The common ancestor requirement should be clearer if you review what a three-way merge actually is.

Using the node labels in your diagram, suppose your repo has a file foo.

In commit C2 (the common ancestor), foo contains:

a
b
c

In commit C4, foo is changed to:

aa
b
c

In commit C5, foo is changed to:

a
b
cc

Merging C4 and C5 should have no conflicts, resulting in:

aa
b
cc

Taking line 1 as an example, without looking at the common ancestor, Git would only know that this line is different between commits C4 and C5, but not which version (a or aa) should be kept in the merge result, so Git would have to mark that as a merge conflict. To resolve the conflict, the user would have to compare foo as it appears in the common ancestor to foo as it appears in C4 and C5. Since line 1 was changed in only one of those commits (C4), the change (aa) should be kept. By taking the common ancestor into account, Git can do this step automatically.

If C5 had also changed line 1 (say, to aaaa), then Git wouldn't know which version would be best to keep. This would result in a merge conflict that the user would need to resolve manually.

like image 20
jjlin Avatar answered Oct 20 '25 05:10

jjlin