DESCRIPTION

Merge conflicts can happen during a git merge, git rebase, git cherry-pick, git pull, git revert, or any other command that does a merge. All of those commands use the same merge algorithm, and the process for resolving a merge conflict is always very similar.

There are 3 ways to handle a merge conflict:

  • Resolve the conflict. (see HOW TO RESOLVE A MERGE CONFLICT below for details)

  • Stop the operation and return your branch to its original state with the appropriate --abort command, for example git merge --abort or git rebase --abort. See EXAMPLE: GIT STATUS OUTPUT below for how to find the command to run.

  • Or (if you’re in a multi-step operation like a rebase) skip the problematic commit with the appropriate --skip command.

WHAT IS A MERGE CONFLICT?

When Git merges two commits together, it looks at the changes that each side has made and combines those changes. For example, if one side edited lines 1-5 of hello.py and the other side edited lines 20-25 of the same file, then it can easily combine them since there’s no overlap.

But if both sides edited overlapping lines of the same file (for example one side edited lines 1-5 and the other edited lines 3-6), Git will not try to guess how to combine those changes. This is called a "merge conflict".

When this happens, Git shows you both sides' edits and asks you to pick how to resolve them. It:

  • Stages all of the files which were successfully merged

  • For the files with conflicts, it marks them as conflicted, puts both sides' edits in the file, and leaves merge conflict markers that you need to resolve.

Note
Even if Git successfully merges both sides with no conflicts, it’s possible to end up with code that doesn’t work. For example, this can happen if one side renames a function, and the other side adds a call to the old function. This is called a "semantic merge conflict".

MERGE CONFLICT MARKERS

When there’s a merge conflict, Git will update the conflicted file to include merge conflict markers <<<<<<<, =======, and >>>>>>>. For example, here’s a merge conflict where both sides edited a list of fruits in different ways — one side has "cherry" and the other side has "banana":

FRUITS = [
    "apple",
<<<<<<< HEAD
    "cherry",
=======
    "banana",
>>>>>>> add-fruit
    "mango",
    "orange",
]

The lines from one side of the merge conflict is between <<<<<<< and =======, and the lines from the other side is between ======= and >>>>>>>. See "OURS" AND "THEIRS" below for a full explanation of which side is which.

HOW TO RESOLVE A MERGE CONFLICT

The process for resolving a merge conflict is:

  1. Run git status to get a list of files with merge conflicts.

  2. For each one, find the conflict markers (the <<<<<<<, =======, >>>>>>>) and edit the file to fix the conflict.

  3. Run git add FILENAME for each file to mark the conflict as resolved.

  4. Run the appropriate --continue command to continue the operation that was interrupted by the conflict, for example git merge --continue or git rebase --continue. See EXAMPLE: GIT STATUS OUTPUT below for how to find the command to run.

    Note: During a git merge, git commit and git merge --continue do the same thing.

EXAMPLE OF RESOLVING A MERGE CONFLICT

If you see this in your code during a merge conflict:

FRUITS = [
    "apple",
<<<<<<< HEAD
    "cherry",
=======
    "banana",
>>>>>>> add-fruit
    "mango",
    "orange",
]

Then you might edit that part of the code like this, which includes the fruits from both sides of the conflict:

FRUITS = [
    "apple",
    "banana",
    "cherry",
    "mango",
    "orange",
]

TOOLS FOR HANDLING MERGE CONFLICTS

Here are some ways to get extra context while handling a merge conflict:

  • There are many graphical "merge tools" for Git, which will normally show you the different versions of the code side by side. If you have a mergetool configured, git mergetool will launch it. See also merge.tool in git-config(1) for a list of the mergetools Git supports.

  • You can set the configuration variable merge.conflictstyle=diff3. See DIFF3 below for more.

  • git log --merge --patch <filename> will list all commits which caused the merge conflict for <filename>, and the diff of how they changed the file.

  • Look at the original files. git show :1:filename shows the common ancestor, git show :2:filename shows the "ours" version, and git show :3:filename shows the "theirs" version. See "OURS" AND "THEIRS" below for more on "ours" and "theirs".

Here are some ways to track your progress while handling a conflict:

  • Use git status to get a list of files with conflicts

  • Use git diff --check to make sure you haven’t left any merge conflict markers in a file by accident. It will print "leftover conflict marker" if it finds any.

  • Use git diff AUTO_MERGE to show what changes you’ve made so far to resolve the conflicts. See EXAMPLE OF USING AUTO_MERGE below for more.

EXAMPLE: GIT STATUS OUTPUT

When you’re in a merge conflict, you can find out what commands to run to handle the conflict by running git status.

For example, this git status output tells you that:

  • git rebase --abort will safely bring your branch back to its original state

  • you should run git rebase --continue when you’re done resolving all the conflicts

  • the conflicts in fruits.py haven’t been marked as resolved

$ git status
You are currently rebasing branch 'main' on '58a9fcc'.
  (fix conflicts and then run "git rebase --continue")
  (use "git rebase --skip" to skip this patch)
  (use "git rebase --abort" to check out the original branch)

Unmerged paths:
  (use "git restore --staged <file>..." to unstage)
  (use "git add <file>..." to mark resolution)
        both modified:   fruits.py

DIFF3

By default, Git doesn’t include the original code when formatting a merge conflict. To include the original code, you can set the configuration option merge.conflictstyle to diff3. This extra context can make it much easier to understand what’s happening in a merge conflict.

Here’s an example of what a merge conflict would look like when using diff3. There’s an extra section (between ||||||| and =======) with the original code.

FRUITS = [
    "apple",
<<<<<<< HEAD
    "cherry",
    "mango",
||||||| 1c22e48
    "banana",
    "cherry",
    "mangoooo",
=======
    "banana",
    "mango",
>>>>>>> add-fruit
    "orange",
]

With this view, you can see that both sides fixed a spelling mistake in "mango", and each removed one fruit from the list. This makes it more clear how to resolve the merge conflict: since one side removed banana and one side removed cherry, it would probably make sense to remove both from the list, like this:

FRUITS = [
    "apple",
    "mango",
    "orange",
]
Note
zdiff3 is an alternative to diff3 that makes the merge conflict shorter by making it more ambiguous. See git-config(1) for more.

"OURS" AND "THEIRS"

Sometimes during a merge conflict, Git will use the terms "ours" and "theirs" (or "us" and "them"). For example, git status might say that a file was deleted by us.

"Ours" and "theirs" are both commits: "ours" is the current HEAD commit, and "theirs" is the other side being merged.

The first part of a merge conflict (between <<<<<<< and =======) is from the "ours" side, and the second part (between ======= and >>>>>>>) is from the "theirs" side.

FRUITS = [
    "apple",
<<<<<<< HEAD
    "cherry",                      <- ours
=======
    "banana",                      <- theirs
>>>>>>> add-fruit
    "mango",
    "orange",
]

During a rebase, it can seem "upside down" because the "ours" commit is from the branch you’re rebasing on (for instance main in git rebase main).

These terms in Git all mean the same thing when dealing with a merge conflict:

  • "common ancestor" and "base". The files from this commit are "in stage 1".

  • "ours", "us", and HEAD. The files from this commit are "in stage 2".

  • "theirs", "them". The files from this commit are "in stage 3".

If you’re confused about what something like "deleted by us" means, it’s often easiest to use some of the tools from TOOLS FOR HANDLING MERGE CONFLICTS above to get more context. Finding the commit that deleted the file and seeing why is usually more helpful than trying to abstractly reason through what "us" means.

EXAMPLE OF USING AUTO_MERGE

git diff AUTO_MERGE will show what changes you’ve made so far to resolve conflicts. AUTO_MERGE is a reference that Git creates during a merge. It contains the result of running the merge algorithm.

For example, if we resolved the conflict by adding both "banana" and "cherry" in order, the diff would look like this:

 FRUITS = [
     "apple",
-<<<<<<< HEAD
-    "cherry",
-=======
     "banana",
->>>>>>> add-fruit
+    "cherry",
     "mango",
     "orange",
 ]
Note
AUTO_MERGE is only set if you’re using the default Git merge algorithm.

SEE ALSO

GIT

Part of the git(1) suite