These chevron-ish markers (<<<<<<<
and the like) are conflict markers. This particular set, which includes the |||||||
markers, is from the diff3
conflict style. The default merge
conflict style omits the middle section.
The sections in the first part, <<<<<<<
through |||||||
, come from the current commit. The sections in the second part, |||||||
through =======
, come from the merge base (which we'll define in a moment). The sections in the third part, =======
through >>>>>>>
, come from the other commit.
Longer but more useful
To understand what these mean, remember that any git merge
operation has not two but three inputs. One of the three inputs is your current checkout, aka the HEAD
or @
commit. Normally, this is the newest commit in the branch you have checked out. The second input is based on the git merge
command that you ran.1 For instance, if you ran:
git merge theirbranch
then the second input is the commit at the tip of branch theirbranch
; if you ran:
git merge origin/master
then the second input is the commit to which your origin/master
points. Either way, both of these are commits—snapshots full of files, where the files in your HEAD
commit are the same as, or different from, the files in their commit. The differences between your files and their files are not directly relevant though: the key commit is a third commit, called the merge base.
Git finds the merge base commit for you automatically. The merge base is, in effect, the best shared commit that comes before the other two. Remember that the goal of a merge is to combine work, and in order to do so, Git needs to find out what you changed and what they changed. But each commit is a snapshot, not a set of changes—so Git has to work backwards from your commit and their commit, to find a commit that both of you shared when you started. That's the merge base.
Having found the merge base, Git now performs two diffs. One compares the merge base to your current commit: that's what you changed. The second diff compares the merge base to their commit: that's what they changed. Then Git combines the two sets of changes. The combined changes get applied to the merge base, to give the final merge result.
When you change a file and they don't touch the file at all, combining your changes with their nothing means the result is your changes. Applying those to the base file produces your file. Likewise, when they change a file and you don't, combining your nothing with their changes means the result is their changes, and applying those to the base file produces their file. So these are very easy.
The hard part occurs when you and they both changed the same file. Now Git really does have to combine different changes. If your changes are to lines that they didn't touch, and their changes are to lines that you didn't touch, Git can combine those: it just takes both changes. If you changed some line and they made the exact same change, Git can combine that too: it just takes one copy of the change. The really hard part, which results in a merge conflict, occurs when you changed some lines, and they changed the same lines, in a different way.
For that case, Git writes the conflicted changes into the work-tree copy of the file, surrounded by these conflict markers. The part above the conflict marker region has been successfully combined—or at least, Git thinks it has—and the same applies to the part below the marker region. The part in between is where Git could not decide whether to prefer your change, in the first segment, or theirs, in the last. The middle part, shown only if you choose diff3
style, is what the original lines looked like.
1Note that if you ran git pull
to get to this point, git pull
ran git merge
for you. So you may not have run git merge
directly, but you did invoke git merge
.
The cherry-pick and revert commands use the Git merge machinery too. So do git stash
and some cases of git apply
or git am
. So you can see these merge conflicts for these commands as well. The definition of merge base for these operations is different, though, so it becomes harder to see how you got the conflict.
Another side effect of diff3 vs merge
When there is a conflict, if you have the diff3
style selected, Git has to show you the base version—the entire section where the conflict occurs. But when you have the merge
style selected, Git can omit the base version, and show just the --ours
and --theirs
versions. This means that if it can partially combine the conflicted region, it does so, leaving only the uncombined region surrounded by markers. For instance:
<<<<<<< HEAD
please fix a spelling error
and ok, I changed this
||||||| merged common ancestors
please fix a speeling error
and change this
=======
please fix a spelling error
and change this to something different
>>>>>>> theirs
Here, we and they fixed the spelling error the same way (replacing speeling
with spelling
), but we changed the second line differently. With the diff3 style, you see the base version and both end-point versions.
If we choose the merge
style, Git sees that we and they fixed the spelling error the same way, and we see instead:
please fix a spelling error
<<<<<<< HEAD
and ok, I changed this
=======
and change this to something different
>>>>>>> theirs
Often, this is kind of nice—but sometimes it means you can't tell at all what the original base was, because the conflict is between something and nothing, i.e., one of us or them deleted a line when the other of us or them changed it. I find the diff3
style far easier to read in general, but the merge
style is the default.