1.2 Conflicts are a 3-sided coin

Book can be downloaded from here

Let’s work on our first example from a real project. In this case, git itself.

1.2.1 Example 3 - a git conflict

From git’s repo, checkout revision 80648bb3f2 and merge 20a5fd881a 8. You end up with a conflict in pack-bitmap.c:

Listing 1.34:example 3 - Conflict in pack-bitmap.c
671        struct bitmap *objects = bitmap_git->result; 
672 
673<<<<<<< HEAD 
674        ewah_iterator_init(&it, type_filter); 
675======= 
676        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
677                return; 
678 
679        init_type_iterator(&it, bitmap_git, object_type); 
680>>>>>>> 20a5fd881a 
681 
682        for (i = 0; i < objects->word_alloc &&

I hear you this time. Let’s keep all the lines, you say? Which block should come first? HEAD or the other branch’s? Maybe the call to ewah_iterator_init() should be placed between the conditional and the call to init_type_iterator() on the other branch? Perhaps all the lines should be removed, actually? Maybe we just need to keep only a part of it?

Are all of those scenarios possible? Ah, yes, they are all possible. And are they all correct? Ah, nope. Given that they end up being very different in terms of what the code will end up doing, not all of them are correct. But then, is it a guessing game we play in order to solve conflicts? Nope, no need to guess. You may not be aware of it yet but all you need is a little bit more information... information that, by the way, is not provided to us in the conflict as we see it there. Let me show you some possibilities with a little more information so you can see what’s going on.

Example 3 - Scenario 1

For the sake of explanation, assume that the file on the common ancestor 9 is like this, at around those lines:10

Listing 1.35:example 3 - Scenario 1 - common ancestor code
671        struct bitmap *objects = bitmap_git->result; 
672 
673        ewah_iterator_init(&it, type_filter); 
674        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
675                return; 
676 
677        init_type_iterator(&it, bitmap_git, object_type); 
678 
679        for (i = 0; i < objects->word_alloc &&

If this were the case, that would tip us that, based on the conflict, each one of the branches removed one piece of the original code. HEAD removed the conditional from line 674 and the call to init_type_iterator(). The other branch removed the call to ewah_iterator_init().

Then conflict resolution would be:

Listing 1.36:example 3 - Scenario 1 - conflict resolution
671        struct bitmap *objects = bitmap_git->result; 
672 
673        for (i = 0; i < objects->word_alloc &&
Example 3 - Scenario 2

Now assume that the common ancestor file looks like this:

Listing 1.37:example 3 - Scenario 2 - common ancestor code
671        struct bitmap *objects = bitmap_git->result; 
672 
673        ewah_iterator_init(&it, type_filter); 
674        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
675                return; 
676 
677        for (i = 0; i < objects->word_alloc &&

In this case, HEAD removed the conditional started on line 674, the other branch removed the call to ewah_iterator_init() and added a call to init_type_iterator(). That points to having this as the conflict resolution:

Listing 1.38:example 3 - Scenario 2 - conflict resolution
671        struct bitmap *objects = bitmap_git->result; 
672 
673        init_type_iterator(&it, bitmap_git, object_type); 
674 
675        for (i = 0; i < objects->word_alloc &&

Example 3 - Scenario 3

Finally, assume that the common ancestor file looks like this:

Listing 1.39:example 3 - Scenario 3 - common ancestor code
671        struct bitmap *objects = bitmap_git->result; 
672 
673        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
674                return; 
675 
676        for (i = 0; i < objects->word_alloc &&

In this scenario, HEAD removed the conditional started on line 673, added a call to ewah_iterator_init(). The other branch kept the conditional but added a later call to init_type_iterator(). This begs for yet another different resolution. We need to remove the conditional and keep the two new calls. Which one should come before? That’s a fairly good question to ask and seeing the code alone won’t be able to tell us. You might need more background knowledge to be able to solve it properly, or check the requirements that brought in each call11 . Let’s assume, for the sake of moving forward with the example, that we figure out that we should place the call to init_type_iterator() before the call to ewah_iterator_init(). Then conflict resolution would be:

Listing 1.40:example 3 - Scenario 3 - conflict resolution
671        struct bitmap *objects = bitmap_git->result; 
672 
673        init_type_iterator(&it, bitmap_git, object_type); 
674 
675        ewah_iterator_init(&it, type_filter); 
676 
677        for (i = 0; i < objects->word_alloc &&

So 3 different scenarios for the same conflict. Each scenario meant a different conflict resolution. Now, what I want you to realize is this hard cold truth: the common ancestor 12 is driving conflict resolution. If you do not consider the common ancestor you would be.... what would be the best word to describe it? Oh, yes! Guessing! And I don’t care how educated your guess is (in terms of background knowledge of the code you are working with). You would have to have a memory that beats that provided by git in terms of knowing what code looked like in the past so that I stop calling it so.

Having cleared that up, let’s continue with the current example. What does the common ancestor look like in this case, for real? Finding that out is a process that involves more than one step so let’s start.

Example 3 - Solving the conflict for real

First things first. What is the common ancestor?

Listing 1.41:example 3 - finging common ancestor
$ git merge-base HEAD MERGE_HEAD 
d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783

The common ancestor is revision d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783. On that revision, is the file called the same? Let’s hope so! Did the content change much? Perhaps some lines were added or deleted before the block we are working with? Let’s hope it didn’t change that much! 13 Let’s give it a try:

Listing 1.42:example 3 - checking ancestor code
$ git blame -s -L 671,681 d0654dc30 -- pack-bitmap.c 
fff42755efc 671)        while (roots) { 
fff42755efc 672)                struct object *object = roots->item; 
fff42755efc 673)                roots = roots->next; 
fff42755efc 674) 
3ae5fa0768f 675)                if (find_pack_entry_one(object->oid.hash, bitmap_git->pack) > 0) 
fff42755efc 676)                        return 1; 
fff42755efc 677)        } 
fff42755efc 678) 
fff42755efc 679)        return 0; 
fff42755efc 680) } 
fff42755efc 681)

Oops! We ran out of luck! 14 The file hadn’t been renamed (great!) its previous content did change (bummer!) and so the section we need to look at is not at the same position of the conflict we are dealing with. After surfing the file a little bit, we find the block we care about, some 40 lines before where we were hoping it would be:

Listing 1.43:example 3 - checking ancestor code 2nd attempt
$ git blame -s -L 631,638 d0654dc308b0ba76dd8ed7bbb33c8d8f7aacd783 -- pack-bitmap.c 
3ae5fa0768f 631)        struct bitmap *objects = bitmap_git->result; 
3ae5fa0768f 632) 
3ae5fa0768f 633)        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
fff42755efc 634)                return; 
fff42755efc 635) 
fff42755efc 636)        ewah_iterator_init(&it, type_filter); 
fff42755efc 637) 
fff42755efc 638)        while (i < objects->word_alloc && ewah_iterator_next(&filter, &it)) {

And now we could compare what each branch did. On HEAD, we removed the conditional started on line 633.15 . On the other branch, we removed the call to ewah_iterator_init() and we added a call to init_type_iterator(). Which means that in our conflict resolution we would keep the call to init_type_iterator() only because the other parts that were present on the common ancestor are gone:

Listing 1.44:example 3 - final resolution
671        struct bitmap *objects = bitmap_git->result; 
672 
673        init_type_iterator(&it, bitmap_git, object_type); 
674 
675        for (i = 0; i < objects->word_alloc &&

And by comparing this with 0df82d99da you should find no meaningful differences. 16

I hope this time you really got why it’s so important to be able to see the common ancestor on a conflict. As I said before, if you don’t consider the common ancestor, you are making an educated guess at best, a total disaster at worst. I agree it is a lot of work if we need to go check what the common ancestor code looks like every single time we have a conflict.

What if the file had been renamed? Can we figure out what the original name was easily?

Before you burn the book in frustration17 , let me show you a little git trick. git can actually do the work of showing you what the common ancestor looks like without additional work on your part. By setting merge.conflictStyle to diff3 18, git will kindly add what the common ancestor looked on the section of code that is related to the conflict. Let me show you the current conflict after applying this option for your own amusement:

Example 3 - Solving the conflict for real with diff3

Listing 1.45:example 3 - conflict with diff3 applied
671        struct bitmap *objects = bitmap_git->result; 
672 
673<<<<<<< HEAD 
674        ewah_iterator_init(&it, type_filter); 
675||||||| d0654dc308 
676        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
677                return; 
678 
679        ewah_iterator_init(&it, type_filter); 
680======= 
681        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
682                return; 
683 
684        init_type_iterator(&it, bitmap_git, object_type); 
685>>>>>>> 20a5fd881a 
686 
687        for (i = 0; i < objects->word_alloc &&

Wow! We get to see the common ancestor code between the sections of each branch. git is also kind enough to tell us the common ancestor revision19 . Now we can see what each one of the branches did.

In order to solve our conflict, first, start working from HEAD:

Listing 1.46:example 3 - step 1
673<<<<<<< HEAD 
674        ewah_iterator_init(&it, type_filter); 
675||||||| d0654dc308

Then consider how the other branch changed from the common ancestor:

Listing 1.47:example 3 - step 2
675||||||| d0654dc308 
676        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
677                return; 
678 
679        ewah_iterator_init(&it, type_filter); 
680======= 
681        if (bitmap_git->reuse_objects == bitmap_git->pack->num_objects) 
682                return; 
683 
684        init_type_iterator(&it, bitmap_git, object_type); 
685>>>>>>> 20a5fd881a

The call to ewah_iterator_init() on line 679 was removed and a call to init_type_iterator() was added on line 684. So we replicate that on HEAD:

Listing 1.48:example 3 - step 3
673<<<<<<< HEAD 
674        init_type_iterator(&it, bitmap_git, object_type); 
675||||||| d0654dc308

And we can now remove the remaining conflict block pieces and markers:

Listing 1.49:example 3 - Done!
671        struct bitmap *objects = bitmap_git->result; 
672 
673        init_type_iterator(&it, bitmap_git, object_type); 
674 
675        for (i = 0; i < objects->word_alloc &&

See? No hassle!

But come on! It is possible to survive solving conflicts without seeing the common ancestor block, right? But of course! Just like it’s possible to develop software without using any unit tests whatsoever, if you know what I mean. It’s not like we need it like oxygen or water. But I already told you the what it is like when you decide not to look at the common ancestor: It’s a guess. Using this option to see the common ancestor code on a conflict is the single most important tip in this handbook.

1.2.2 Tips

1.2.3 Exercises

Exercise 3

From git’s repo, checkout revision fe870600fe and merge 1bdca81641 20. Solve both conflicts (there are 2 conflicting files, one conflict section on each one of the files). Solution is here.

Copyright 2020 Edmundo Carmona Antoranz