Git : Merge Conflicts

After seeing about Merging and Rebasing , it is important to know about merge conflicts. Merge conflicts are one of the common problems found in a git based project.

During merges and rebases, changes from one branch is pushed to another , or is merged to form a converging point. The main problem with this approach is when trying to merge 2 branches is that both the branches can have different versions for a same file. So in this situation , logically git does not know which version of the file belongs to the actual new version. Git tries somethings before giving up.

‘Merging’

merge

During a merge , git notes down all the changes induced by the commits and applies them to the resultant file in the merged state . Git often acheives this without any troubles . If there are 2 or more changes in a file induced by different commits in differing branches, a new version of the file is created and both the changes are included. Git understands that changes made to different lines in the same file can be merged literally and doesnt need supervision often . This is often called automerging .

Consider a file ‘file6’

$ gl
* 88d5446 (HEAD -> bugfix) Merge branch 'bugfix2' into bugfix
|\
| * 57658fe (bugfix2) added line 3
* | 621d9f9 added line 4
|/
* 7b9cd5e merged
|\
| * aa43a83 added 1 line
* | 00f07af added 2 lines
|/
* ad9631e commit 13
* ebc508e commit 12
* 0e180e8 commit 9
* 79d8019 commit 8
* 75d11f0 commit 7
* f6338e0 (master) Sixth commit
* 5c0595d fifth file
* b4798cb Fourth commit
* 71764ed fajfgj
* 677358d second file
* d6ed37b first file

$ git show 7b9cd5e:file6
this is line 1

and this is line 2

$ git show 621d9f9
commit 621d9f9365ab058022495da4640baad2009a8571
Author: harish1996
Date: Sun Jun 3 11:41:17 2018 +0530

added line 4

diff --git a/file6 b/file6
index c664986..462dbc0 100644
--- a/file6
+++ b/file6
@@ -1,4 +1,4 @@
this is line 1
-
+this is line 4
and this is line 2

$ git show 57658fe
commit 57658fe70a080cd95b0abb99c2920b5c087e8b33
Author: harish1996
Date: Sun Jun 3 11:40:39 2018 +0530

added line 3

diff --git a/file6 b/file6
index c664986..92b31c8 100644
--- a/file6
+++ b/file6
@@ -1,4 +1,4 @@
this is line 1

and this is line 2
-
+this is line 3

Since the changes are in different lines . When we used git merge, git automerged it with the message

allofit

$ git merge bugfix2
Auto-merging file6
Merge made by the 'recursive' strategy.
file6 | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

The resultant file is

$ cat file6
this is line 1
this is line 4
and this is line 2
this is line 3

The problem arises only when git finds out there are 2 different versions of a line in the same file. It is machine-ly impossible for it to decide which change to keep and which to omit. Just like a robot cant decide between a child and a great scientist, when trying to save them from danger ( Refer Enthiran Movie ). It is a hypothetical situation requiring human attention.

hypothetical

What is a Merge Conflict ?

Merge conflicts are situations where git cannot determine which change to choose, while merging a file between 2 branches. When git finds 2 changes in the same line, git stops the merge operation and waits for the user to approve which change is to be included. Whenever a merge conflict occurs, git warns us about the situation and stops. Inorder to aid the user git uses markers to indicate that the particular segment is the reason for the merge conflict

Let us take this tree

$ gl
* 88d5446 (HEAD -> bugfix2, bugfix) Merge branch 'bugfix2' into bugfix
|\
| * 57658fe added line 3
* | 621d9f9 added line 4
|/
* 7b9cd5e merged
|\
| * aa43a83 added 1 line
* | 00f07af added 2 lines
|/
* ad9631e commit 13
* ebc508e commit 12
* 0e180e8 commit 9
* 79d8019 commit 8
* 75d11f0 commit 7
* f6338e0 (master) Sixth commit
* 5c0595d fifth file
* b4798cb Fourth commit
* 71764ed fajfgj
* 677358d second file
* d6ed37b first file

We are now in branch bugfix2. So let us introduce two different changes in 2 different branches in the same line of the same file.

$ gl bugfix
* 21a556e (HEAD -> bugfix) changed line 4
* 88d5446 Merge branch 'bugfix2' into bugfix
|\
| * 57658fe added line 3
* | 621d9f9 added line 4
|/
* 7b9cd5e merged
|\
| * aa43a83 added 1 line
* | 00f07af added 2 lines
|/
* ad9631e commit 13
* ebc508e commit 12
* 0e180e8 commit 9
* 79d8019 commit 8
* 75d11f0 commit 7
* f6338e0 (master) Sixth commit
* 5c0595d fifth file
* b4798cb Fourth commit
* 71764ed fajfgj
* 677358d second file
* d6ed37b first file

$ gl bugfix2
* 86f0dc2 (bugfix2) changed line 4
* 88d5446 Merge branch 'bugfix2' into bugfix
|\
| * 57658fe added line 3
* | 621d9f9 added line 4
|/
* 7b9cd5e merged
|\
| * aa43a83 added 1 line
* | 00f07af added 2 lines
|/
* ad9631e commit 13
* ebc508e commit 12
* 0e180e8 commit 9
* 79d8019 commit 8
* 75d11f0 commit 7
* f6338e0 (master) Sixth commit
* 5c0595d fifth file
* b4798cb Fourth commit
* 71764ed fajfgj
* 677358d second file
* d6ed37b first file

$ git show 21a556e:file6
this is line 1
this is line 6
and this is line 2
this is line 3

$ git show 86f0dc2:file6
this is line 1
this is line 5
and this is line 2
this is line 3

When trying to merge these two branches, hell breaks loose 😛 .

$ git merge bugfix2
Auto-merging file6
CONFLICT (content): Merge conflict in file6
Automatic merge failed; fix conflicts and then commit the result.

Oh my god !!! Something failed … Ahhhhh…. !!

scared

When we open file6 , we can find this dreadful thing git has done..

$ cat file6
this is line 1
<<<<<>>>>> bugfix2
and this is line 2
this is line 3

Solving Merge Conflicts

saveurself

Git adds markers to indicate that there are 2 versions of the same line and asks us to choose between the dark side and light side. To choose, it is enough to edit out the markers , and as soon as we remove the markers , we must be ready to go..

$ cat file6
this is line 1
this is line 5
and this is line 2
this is line 3

I have decided to go with ‘line 5’ version. So what now ? Git has directed us to Automatic merge failed; fix conflicts and then commit the result. . So let us add file6 first and commit that and see what happens.

$ git add file6

$ git commit -m "merging.."
[bugfix 2bd0dd7] merging..

$ gl
* 2bd0dd7 (HEAD -> bugfix) merging..
|\
| * 86f0dc2 (bugfix2) changed line 4
* | 21a556e changed line 4
|/
* 88d5446 Merge branch 'bugfix2' into bugfix
|\
| * 57658fe added line 3
* | 621d9f9 added line 4
|/
* 7b9cd5e merged
|\
| * aa43a83 added 1 line
* | 00f07af added 2 lines
|/
* ad9631e commit 13
* ebc508e commit 12
* 0e180e8 commit 9
* 79d8019 commit 8
* 75d11f0 commit 7
* f6338e0 (master) Sixth commit
* 5c0595d fifth file
* b4798cb Fourth commit
* 71764ed fajfgj
* 677358d second file
* d6ed37b first file

Voila !! The two branches merged… Success !

Easier way to solve merge conflicts ?

Removing the markers may seem easy for small changes , It is very difficult to do when the changes are humongous. So git has saved us the trouble and provided us a tool for resolving merge conflict. It is intuitively named git mergetool .

Mergetool

weapon

git mergetool is a great tool provided by git itself. It provides a neat method to remove merge conflicts by the use of other famous diff like tools like ‘vimdiff’ , ‘meld’ etc. I have personally used meld often. So let us create yet another merge conflict for us to resolve.

I am now creating a merge conflict by removing the commit for the previous merge and trying to merge the same branches again.

$ git reset 21a556e
Unstaged changes after reset:
M file6

$ git merge bugfix2
error: Your local changes to the following files would be overwritten by merge:
file6
Please, commit your changes or stash them before you can merge.
Aborting

$ git stash
Saved working directory and index state WIP on bugfix: 21a556e changed line 4
HEAD is now at 21a556e changed line 4

$ git merge bugfix2
Auto-merging file6
CONFLICT (content): Merge conflict in file6
Automatic merge failed; fix conflicts and then commit the result.

Now to solve the merge conflict let use git mergetool

$ git mergetool

This message is displayed because 'merge.tool' is not configured.
See 'git mergetool --tool-help' or 'git help config' for more details.
'git mergetool' will now attempt to use one of the following tools:
meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc codecompare emerge vimdiff
Merging:
file6

Normal merge conflict for 'file6':
{local}: modified file
{remote}: modified file
Hit return to start merge resolution tool (meld):

$ git add file6

$ git commit -m "merged..."
[bugfix fd45d7b] merged...

$ git show
commit fd45d7bec204d95e039f75056a485024e8a351a2
Merge: 21a556e 86f0dc2
Author: harish1996
Date: Sun Jun 3 12:57:41 2018 +0530

merged...

$ cat file6
this is line 1
this is line 5
and this is line 2
this is line 3

I use meld to resolve merge conflicts. So after trying git mergetool .. This happens..

Screenshot from 2018-06-03 12-56-56

The left _LOCAL side is the content in the branch you are in .. i.e. bugfix . The center portion is the content to be incorporated in the merge. The right _REMOTE side is the content in the branch that is to be merged.

After swapping and editing changes into the center field , which is the change which will be incorporated into the actual branch , we can save that center field , add and commit that changes to the branch which will create a merge commit , like the above.

Back to Branching

As we have seen enough about merging, rebasing and solving merge conflicts , we are now ready to move ahead to more complicated versions of merge and rebase from the next article.

 

4 thoughts on “Git : Merge Conflicts”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s