Merge Conflicts and How to handle them
Conflicts while merging is a frequent part of the Git experience. If there are several developers working on the same file the odds of encountering a merge conflict increases. Most of the time, Git will automatically figure out how to integrate new changes. Conflicts generally arise when two people have changed the same lines in a file, or if one developer deleted a file while another developer was modifying it. In these cases, Git cannot automatically figure out which is correct. Hence, Git will notify the developer performing the merge that conflict is encountered, the rest of the team will be unaware of the conflict. Now, it is the responsibility of the developer performing the merge, to resolve the conflict.
Types of Merge Conflicts
While starting the merge: If there are changes in either the working directory or staging area, while merging, then Git will fail to start the merge. This happens because the pending changes could be overridden by the commits that are being merged. This is the error message provided by Git when this type of merge conflict happens :
error: Entry '<fileName>' not uptodate. Cannot merge. (Changes in working directory) or, error: Entry '<fileName>' would be overwritten by merge. Cannot merge. (Changes in staging area)
This type of conflict can be resolved either by doing git stash save “any_message_to_describe_what_is_saved” (Stashes away any changes in your staging area and working directory in a separate index) OR git checkout <file_name> (throws out your changes), and then the merge can be completed.
During the merge: This occurs because you have committed changes that are in conflict with someone else’s committed changes. Git will do its best to merge the files and will leave things for you to resolve manually in the files it lists. This is the error message provided by Git when this type of merge conflict happens :
CONFLICT (content): Merge conflict in <fileName> Automatic merge failed; fix conflicts and then commit the result.
This type of conflict can be resolved either by manually fixing all the merge conflict for each file OR using git reset ––hard (resets repository in order to back out of merge conflict situation).
Creating a merge conflict
To show a simple example of how a merge conflict can happen, we can manually trigger a merge conflict from the following set of commands in any UNIX terminal / GIT bash :
Step 1: Create a new directory using the mkdir command, and cd into it.
Step 2: initialize it as a new Git repository using the git init command and create a new text file using the touch command.
Step 3: Open the text file and add some content in it, then add the text file to the repo and commit it.
Step 4: Now, its time to create a new branch to use it as the conflicting merge. Use git checkout to create and checkout the new branch.
Step 5: Now, overwrite some conflicting changes to the text file from this new branch.
Step 6: Add the changes to git and commit it from the new branch.
With this new branch: new_branch_for_merge_conflict we have created a commit that overrides the content of test_file.txt
Step 7: Again checkout the master branch, and this time append some text to the test_file.txt from the master branch.
Step 8: add these new changes to the staging area and commit them.
Step 9: Now for the last part, try merging the new branch to the master branch and you will encounter the second type of merge conflict.
So, now we have successfully triggered a merge conflict in Git.
Identifying and Resolving conflicts
As we have experienced from the proceeding example, Git will produce some descriptive output letting us know that a CONFLICT has occurred. We can gain further insight by running the git status command. This is what we will get after running the git status command:
On branch master You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: test_file.txt no changes added to commit (use "git add" and/or "git commit -a")
On opening the test_file.txt we see some “conflict dividers”. This is the content of our test_file.txt :
<<<<<<< HEAD Adding some content to mess with it later Append this text to initial commit ======= Changing the contents of text file from new branch >>>>>>> new_branch_for_merge_conflict
The ======= line is the “center” of the conflict. All the content between the center and the <<<<<<< HEAD line is content that exists in the current branch master which the HEAD ref is pointing to. Alternatively, all content between the center and >>>>>>> new_branch_for_merge_conflict is content that is present in our merging branch.
To resolve our merge conflict, we can manually remove the unnecessary part from any one of the branches, and only consider the content of the branch that is important for further use, along with removing the “conflict dividers” from our file. Once the conflict has been resolved we can use the git add command to move the new changes to the staging area, and then git commit to commit the changes.