Skip to main content
ANVISoftware Solutions
Lesson 8 of 15Beginner15 min

Resolving Conflicts

By the end of this lesson

Read a conflict and resolve it deliberately.

A conflict is Git telling you it found two changes to the same lines and does not know which one you want. It is information, not a failure, and not a sign that you did anything wrong.

Git will combine changes automatically whenever it can work out the answer. Two people editing different files, or different parts of the same file, merge silently. A conflict means the two changes genuinely overlap, and no tool can decide the outcome because the decision requires knowing what the code is for.

When a merge hits a conflict, Git stops partway through. Files it could merge are already staged. Files it could not are left in your working directory with both versions written into them, marked so you can see where the disagreement is.

Nothing is lost at this point and nothing is committed. You are in a paused state that you can either resolve or abandon.

A conflict as it appears in the file
Text
public decimal CalculateTotal(Order order)
{
<<<<<<< HEAD
    var total = order.Lines.Sum(line => line.Price * line.Quantity);
    return Math.Round(total, 2);
=======
    var total = order.Lines.Sum(line => line.NetPrice * line.Quantity);
    return total + CalculateTax(total);
>>>>>>> add-tax-calculation
}

Every marker means something specific:

<<<<<<< HEAD
Start of the version from the branch you are on — the one you were sitting on when you ran the merge. During a rebase this label means something different, so read what follows the marker rather than assuming.
=======
The divider. Everything above it is one side, everything below is the other. It is not part of either version.
>>>>>>> add-tax-calculation
End of the version coming in, labelled with the branch or commit it came from. In this example, the work on the add-tax-calculation branch.
The lines between them
The two competing versions in full, not a summary. Resolving the conflict means deleting all three markers and leaving the code you actually want.

The example above is exactly why blind resolution is dangerous. Work through it deliberately:

  1. Read both sides and say what each one does

    One side rounds the total to two decimal places. The other switches to net prices and adds tax. These are two unrelated improvements that happen to touch the same three lines.

  2. Decide what the correct result is

    Here, neither side alone is right. The answer needs net prices, tax added, and the result rounded. Taking either version wholesale silently discards a real change.

  3. Write that result

    Delete all three marker lines and write the combined version. You are allowed to produce code that appears on neither side — you frequently have to.

  4. Verify it before you stage it

    Build it. Run the tests that cover it. A conflict resolution is new code that has never existed before, and it deserves the same scepticism as any other new code.

  5. Stage the file and finish the merge

    Staging is how you tell Git this file is resolved. Once every conflicted file is staged, complete the merge.

Working through a conflict
Shell
git merge add-tax-calculation
# Git reports the conflict and stops

# Which files need your attention?
git status

# See only the conflicted parts across all files
git diff

# ... edit each file, remove all markers, build and test ...

git add src/OrderTotals.cs

# Complete the merge once everything is staged
git merge --continue

# Or walk away and put the repository back as it was
git merge --abort
  • git status lists conflicted files under "Unmerged paths". That list is your task list, and it shrinks as you stage each file.
  • git diff during a conflict shows the overlapping regions rather than the whole change, which is usually the quickest way to see how much work is genuinely involved.
  • git add on a conflicted file means "I have resolved this". Git does not check your resolution, so staging a file that still contains markers will succeed.
  • git merge --abort returns the repository to its pre-merge state. Use it without embarrassment. Restarting a confusing merge from a clean position is a reasonable decision, not a retreat.

Summary

  • A conflict means two changes overlap and the decision needs human intent
  • Markers show both versions in full: <<<<<<< your side, ======= divider, >>>>>>> incoming side
  • Resolving means deleting all three markers and writing the code that is actually correct, which may match neither side
  • Read and understand both sides first — taking one blindly can delete someone's work silently
  • Staging a file marks it resolved; git merge --abort returns you to a clean starting point

Practice

Attempt each one before opening the solution. Getting it wrong first is how the idea sticks.

Try it yourself

Create a conflict on purpose

In a practice repository, commit a file with one line of text on main. Create a branch and change that line. Switch to main and change the same line differently. Commit both.

Merge the branch into main. Read the conflict markers in the file, then resolve it into a version that keeps something from each side.

Show solution

Creating a conflict deliberately, when you know exactly what both sides say, is the fastest way to stop finding them alarming.

The part worth noticing is that your resolution is a third version, matching neither side. That is normal. Git asked you a question; the answer is whatever the code should be.

Shell
git switch -c change-greeting
# edit greeting.txt
git commit -am "Greet the customer by first name"

git switch main
# edit the same line differently
git commit -am "Include the company name in the greeting"

git merge change-greeting
git status
# resolve greeting.txt, remove all markers
git add greeting.txt
git merge --continue

Think about it

Think about it

Two developers both rename the same method, to different names, in the same commit range. Git reports a conflict.

Why can no tool resolve this automatically, no matter how clever it is?

Show solution

Both changes are valid and neither is newer in any meaningful sense. Choosing between them requires knowing which name describes the method better, which is a judgement about meaning rather than about text.

This is the general shape of every conflict. Git can merge changes whose combination is unambiguous. When the combination requires intent, it stops and asks, because guessing would be worse than pausing.

It is also a hint about process. Two people renaming the same method in the same week suggests the work was not divided clearly, and that is the more useful thing to fix.

Knowledge check

Nothing is recorded and there is no score. The explanation appears either way.

During a conflict, what does the content above the ======= divider represent?
How do you tell Git that you have finished resolving a conflicted file?

Saved in this browser only.