Skip to main content

How to Resolve Merge Conflicts in Git Tutorial

Learn various commands and tools for merging two branches and resolving conflicts in Git, an essential skill for data scientists.
May 2022  · 16 min read

What is a Git Merge Conflict?

Git version control system is all about working as a team and contributing to projects. Developers usually work on isolated branches, and when they are finished, they merge the changes with the main branch. This type of teamwork is highly productive and effective in finding bugs. Sometimes multiple developers are working on the same line of code, and when they try to merge the changes, conflicts arise. 

Git Merge Conflicts Graphic
Simple Example of Git Conflict

The diagram above gives the perfect example of how a typical Git merge conflict occurs. The main branch has a file containing the text “HELLO, WORLD!”. The username abid forks the main branch, and changes the text to “HELLO, CAT!”. While abid is making changes, the original main branch is also being modified to “HELLO, DOG!”. Merging these branches will prompt a merge conflict issue and halt the process.  

The `git merge` command's primary job is to combine two branches and automatically resolve the conflicts. However, from time to time conflicts surface where two people have changed the same line of code or removed critical files that another developer was working on. Git will mark these changes and stop the merging process. In this case, the conflict has not been automatically resolved; rather the developer has to make changes manually or use tools to resolve the conflict. 

Merge Types

Git merge and rebase are the two ways to integrate commits from the target branch to the source branch. Furthermore, Git merge performs either a fast-forward or a no-fast-forward merge. If the head of the target branch exists in the source branch, then by default, the merge type will be a fast-forward merge and if it is missing, then a no-fast-forward merge. Git rebase is another type of merge that resequences the commit history of the target branch. 

Fast-forward Merge

Git Fast Forward Merge

By default, Git merge uses fast-forward to integrate missing commits into the target branch. For example, it is used to update the local branch from a remote server using the pull command. Fast-forward does not raise merge conflict issues as Git will not apply it if the head of the target branch is missing in the source branch. 

No-fast-forward Merge

Git No-fast-forward Merge

A no-fast-forward merge is also called a three-way or true merge. It creates a new commit on a target branch by integrating changes in both the source and target branch. The changes are blended after the last common commit in both branches. In our case, it is after the C. This type of merge will prompt Git merge conflict if the source branch is in dispute with the target branch. In the diagram above, the merge commit (X) is created by integrating the source and the target branch, where K and E are the parents of the merge commit. 

Rebase 

Git Rebase

Git rebase is a bit different from other types. It changes the sequence of target branch commit history. The rebase integrates the source branch in such a way that the target branch contains all the changes from the source branch, followed by all target branch commits after the last common commit. In our case, the last common commit is C, whereas D and E are from the source branch. The K* commit is the same as K with a different commit id. Instead of linking C, it will be linking E. Similar to a no-fast-forward merge, if there are compatibility issues in the source and the target branch, Git will raise an issue to resolve conflict before finalizing rebasing. 

Types of Git Merge Conflicts

There are two types of Git merge conflicts: at the start and during the merging process - Atlassian. In this section, we will learn about both types and the ways to resolve each scenario. 

At the Start of the Merge

Git merge will fail at the start if there are changes in the working directory or staging area. It fails at the start to prevent the changes from being overwritten by incoming merge commits. This happens due to conflicts with local changes, not with other branches or developers. To stabilize the local state, you can use commands such as `git stash`, `git commit`, `git checkout`, or `git reset`.

During the Merge

A failure during the merge means that there is a conflict between the source and target branch where multiple developers have modified the same file. If the automatic merge fails, Git will ask you to resolve issues manually. You can also use third-party tools to assist you in visualizing and integrating the changes.

Commands for Resolving Git Merge Conflicts

In this section, we will learn about various native commands to visualize and resolve the Git merge conflicts. 

Common Commands

Git status is the most frequently used command to display the status of modified files, staging area, and commits. During the merging process, it is used to identify conflicted files.  

git status

The Git log with --merge arguments produces the list of commits that are in conflict with the source branch. 

git log --merge

By default, the `git diff` option will show you the difference between uncommitted changes and previous commits. Git diff is used for comparing branches, commits, and files. It is useful for preventing future merge conflicts. 

git diff 

Commands for Merge Fails at the Start

The checkout is used for undoing changes or switching to a new or old branch. 

git checkout

The Git reset is for reverting the changes in the working directory and staging area. 

git reset --mixed

Commands for Conflicts During the Merge

The --abort argument will stop the merge process and revert the changes to their original state before the merge started. 

git merge --abort

Git reset is usually used during the merging process to revert the conflicted files to their original state.

git reset

Resolve Deleted-Modified File Conflicts

Git conflict will occur if you have deleted the file in the current branch, and someone else has modified it in another branch. In this case, you can either add a file and commit,

git add <filename>

or you can remove the file and commit. 

git rm <filename>

Visual Merge Tools

Merge tools are user-friendly visual tools for identifying and resolving all types of merge conflicts. Some of the tools support additional capabilities such as comparing changes, Git operations, and project and repository management. There are two types of Git merge tools: terminal-only and GUI-based. The terminal-based tools open within PowerShell or Bash, and the GUI-based tools open in a windowed environment. 

To check the list of installed and valid tools, use:

git mergetool --tool-help 

The list consists of all valid tools that can be installed and integrated with git commands.

For example, we have vim and nvim installed by defaults, and if you want to see the difference between an uncommitted file and a previous commit, type:

git difftool --tool=vimdiff3

The vimdiff3 tool highlights the changes and lets you compare commits within the terminal. 

Difference between two versions of the same file in Vimdiff3
Difference Between Two Versions of Same File in Vimdiff3

Meld

Meld is a free and open-source tool that takes resolving merge conflicts to another level. To integrate it with Git, you need to first download, and install the setup from the official site. Next, add it to the global configuration so that by default, Git will launch Meld for resolving conflicts.  

The config commands below are only applicable to Windows users. The only change you have to make is to change the path of the Meld installed file for Mac or Linux. 

git config --global merge.tool meld 

git config --global mergetool.meld.path "C:/Program Files (x86)/Meld/Meld.exe" 

git config --global diff.tool meld

git config --global difftool.meld.path "C:/Program Files (x86)/Meld/Meld.exe"

After setting up defaults, you can type `git difftool` within the Git local directory to launch the Windows version of Meld, or you can `git mergetool` to resolve merge conflicts as shown below.

Resolving a Merge Conflict with Meld in Git
Resolving a Merge Conflict with Meld

VSCode

VSCode provides the best and most popular way for resolving the merge conflict. When Git fails to merge files automatically, the VSCode will highlight the conflicted code and give you four options: accept current changes, accept incoming changes, accept both changes, and compare changes. You can use these options to clean up your file and resolve all pending issues. 

Resolving a Git Merge Conflict with VSCode
Resolving Merge Conflict with VSCode

If you are looking for a complete solution for your Git operations, try GitKraken. It comes with a free client, VSCode extension, and provides a built-in tool for resolving merge conflicts.  

How to Resolve a Git Merge Conflict

In this section, we are going to learn how to create a Git merge conflict and then resolve it. The tutorial is divided into two parts. In the first part, we will learn to resolve Git conflicts locally; the second part is about resolving conflicts with a remote server (GitHub).

Local Merge Conflict

Creating merge conflicts will help us learn how these issues arise in the first place. We can then use creative ways to resolve these problems or even prevent them from happening in the future. 

We will now create a Git repository with a single file and create our first commit to get started. 

  1. Create a folder called datacamp.
  2. Change directory to datacamp.
  3. Initialize Git.
  4. Create a README.md file with the given title.
  5. Stage and commit the changes in a file.
mkdir datacamp
cd datacamp
git init
echo "# How to Resolve Git Merge Conflict" > README.md
git add README.md
git commit -m "first commit"

>>> [main (root-commit) 8199ea2] first commit
>>>  1 file changed, 1 insertion(+)
>>> create mode 100644 README.md

Next, we will create a new branch readme and change the title from “..Git Merge..” to “..Git..”. Add the file and create the commit using -am argument.

git checkout -b readme
echo "# How to Resolve Git Conflict" > README.md
git commit -am "new branch conflict added"

>>> [readme 155f694] new branch conflict added
>>> 1 file changed, 1 insertion(+), 1 deletion(-)

Go back to the main branch and add a new line to the README.md file using >>. By saving the changes and creating commits, we have successfully formed a conflict between two versions of the same file. 

git checkout main
echo "New change in base branch" >> README.md
git commit -am " a line added to base branch Readme file"

>>> [main f1f1874]  a line added to base branch Readme file
>>> 1 file changed, 1 insertion(+)

As we can see, while merging the readme branch, Git has prompted a message saying that the automatic merge has failed, and we have to make changes manually and then commit the result. 

git merge readme

>>> Auto-merging README.md
>>> CONFLICT (content): Merge conflict in README.md
>>> Automatic merge failed; fix conflicts and then commit the result.

We will resolve the issue manually by opening and editing the file in the Notepad. The image below shows the arrow with HEAD, a divider, and a different direction arrow with a readme. The HEAD part shows the existing changes in the main branch, and the readme part is the branch that we want to merge, which consists of a different heading. 

Resolving a Merge Conflict ManuallyResolving a Merge Conflict Manually 

To resolve the problem, we will remove the readme branch part, arrows, and divider. The final version of the file should look clean, as shown below. 


Conflict Resolved 

After we add the file and create a commit, the merge conflict will be resolved. It is the most common and simplest way of resolving issues. You can also use an integrated development environment (IDE) to resolve issues faster.

git commit -am "conflict resolved in file README.md"
>>> [main 9994a29] conflict resolved in file README.md

Remote Merge Conflict

For creating and resolving remote merge conflicts, we need to create a new repository on GitHub.

Creating a New Repository on GitHub
Creating a New Repository on GitHub

Next, add remote name (origin) with address to the repository and push all the changes from a local repository to the remote main branch using upstream.

git remote add origin https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
git push --set-upstream origin main


>>> Enumerating objects: 12, done.
>>> Counting objects: 100% (12/12), done.
>>> Delta compression using up to 4 threads
>>> Compressing objects: 100% (6/6), done.
>>> Writing objects: 100% (12/12), 998 bytes | 499.00 KiB/s, done.
>>> Total 12 (delta 2), reused 0 (delta 0), pack-reused 0
>>> remote: Resolving deltas: 100% (2/2), done.
>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>>  * [new branch]      main -> main
>>> branch 'main' set up to track 'origin/main'.

To create a conflict, we need to make changes in the remote and local README.md file. You can use the GitHub file editor to change “..Git merge..” to “..Sit-Merge..” and then commit the changes. 

Making Changes in GitHub Editor
Making Changes in GitHub Editor

Then, in the local repository, change the README.md file to only add a simple title and commit the changes. 

echo "# How to Resolve Merge Conflicts in Git Tutorial" > README.md
git commit -am "local branch changes in README.md"

>>> [main c677a13] local branch changes in README.md
>>>  1 file changed, 1 insertion(+), 4 deletions(-)

Finally, push the changes to the remote server. Notice that Git has raised the error with hints on how to eliminate the issue. 

git push


>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>>  ! [rejected]        main -> main (fetch first)
>>> error: failed to push some refs to 'https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git'
>>> hint: Updates were rejected because the remote contains work that you do
>>> hint: not have locally. This is usually caused by another repository pushing
>>> hint: to the same ref. You may want to first integrate the remote changes
>>> hint: (e.g., 'git pull ...') before pushing again.
>>> hint: See the 'Note about fast-forwards' in 'git push --help' for details.

We will follow the simplest hint, which is to pull the file from the remote server before pushing. 

Pull the file failed due to a merge conflict in the README.md file. We could fix it manually using Notepad, but this time we will use a visual tool to assist us in this process. 

git pull


>>> remote: Enumerating objects: 5, done.
>>> remote: Counting objects: 100% (5/5), done.
>>> remote: Compressing objects: 100% (2/2), done.
>>> remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
>>> Unpacking objects: 100% (3/3), 681 bytes | 75.00 KiB/s, done.
>>> From https://github.com/kingabzpro/DataCamp-Git-Merge-Guide
>>>    aaf149d..49b7d14  main       -> origin/main
>>> Auto-merging README.md
>>> CONFLICT (content): Merge conflict in README.md
>>> Automatic merge failed; fix conflicts and then commit the result.

Merge tool Meld will identify conflicted files and show them in the Meld GUI application.   

git mergetool

>>> Merging:
>>> README.md

>>> Normal merge conflict for 'README.md':
>>>   {local}: modified file
>>>   {remote}: modified file

There are three columns: README_LOCAL_473.md, README.md, and README_LOCAL_473.md. If you think the remote changes are valid, then click on the black arrow in the remote column; and if you want local changes to persist, then click on the black arrow on the local column. It is that simple. 

Git: Conflict Resolved Using mergetool Meld
Conflict Resolved Using mergetool Meld

After making changes, save the file and commit. As you can see, pushing a file to a remote server does not raise a merge conflict error.

git commit -am "remote main branch conflict resolved"
git push

>>> Enumerating objects: 16, done.
>>> Counting objects: 100% (16/16), done.
>>> Delta compression using up to 4 threads
>>> Compressing objects: 100% (6/6), done.
>>> Writing objects: 100% (10/10), 1.08 KiB | 550.00 KiB/s, done.
>>> Total 10 (delta 2), reused 0 (delta 0), pack-reused 0
>>> remote: Resolving deltas: 100% (2/2), completed with 1 local object.
>>> To https://github.com/kingabzpro/DataCamp-Git-Merge-Guide.git
>>>    49b7d14..8f5c3aa  main -> main

We have successfully resolved both local and remote merge conflicts. These conflicts are dealt with daily by data scientists and machine learning engineers. To improve your skills in Git operations, take an Introduction to Git course. 

Conclusion

Resolving Git merge conflicts is a complex and highly risky task as you can break the software by merging defective code. Merge tools provide a user-friendly environment with a safer way to detect and resolve merge conflicts. In this tutorial, we have learned why Git conflicts occur and how to resolve them. We have also covered various merge and conflict types, useful Git commands, and visual tools. In the final section, we created a merge conflict and resolved it in a local and remote repository. 

If you are new to Git and want to learn how it works, then read: Intro to Git and GitHub Tutorial

← Back to Tutorials