datarekha

Resolving merge conflicts

Git stopped the merge and printed CONFLICT. Learn why it happens, what the file markers mean, and the exact steps to fix it safely.

9 min read Intermediate Git Lesson 9 of 15

What you'll learn

  • Why Git raises a conflict: the same lines changed on both branches and Git cannot auto-pick a winner
  • How to read a conflicted file: the three sections separated by conflict markers, and what HEAD vs. incoming means
  • The resolution loop: edit the file, remove every marker, git add, then git commit

Before you start

Why conflicts happen

Git is good at merging. When two branches each change different lines, Git combines them silently and moves on. A conflict happens only when both branches change the same lines — at that point Git has two valid candidates for the same content and no policy for choosing between them, so it stops and hands the decision back to you.

Here is the classic setup: main and feature both edited the same line in greeting.py. When you merge feature into main, Git cannot auto-resolve the overlap.

Shared commitgreeting = “Hello”maingreeting = “Hi there”featuregreeting = “Hey!”CONFLICT — merge stopped
Both branches changed the same line. Git stops at the merge and waits for you to decide.

What a conflicted file looks like

When a conflict occurs, Git rewrites the affected file in place, embedding conflict markers to show you both versions side by side. Here is a real example:

def greet(name):
<<<<<<< HEAD
    greeting = "Hi there"
=======
    greeting = "Hey!"
>>>>>>> feature
    return f"{greeting}, {name}!"

Breaking down the three sections:

  • Everything between the opening seven-less-than marker and the separator line of equals signs is the HEAD side — the content from your current branch (the one you ran git merge from).
  • Everything between the separator and the closing seven-greater-than marker is the incoming side — the content arriving from the branch you are merging in.
  • Lines outside both marker pairs were not in conflict and are already correct.

The labels after the opening and closing markers are branch names (or commit SHAs when merging a detached HEAD).

Checking the status

Before touching anything, confirm which files need attention:

git status

Git lists conflicted files under “Unmerged paths”. Every file in that list must be resolved before the merge can complete. Files Git handled automatically are already staged; leave those alone.

The resolution loop

Resolving a conflict is a four-step loop, repeated for every conflicted file:

1. Open the file and decide on the final content.

Pick one side, combine ideas from both, or write something entirely new — whatever is correct. There is no rule that says you must keep either version verbatim.

2. Remove every conflict marker.

Delete the opening marker line, the separator line, and the closing marker line. The file must contain only valid code when you are done.

After editing, the function from the example above might look like:

def greet(name):
    greeting = "Hi there, hey!"
    return f"{greeting}, {name}!"

3. Stage the resolved file.

git add greeting.py

4. Repeat for any remaining conflicted files, then commit.

git status                # confirm no more "Unmerged paths"
git merge --continue      # or: git commit

Git opens your editor for the merge commit message (a default is pre-filled). Save and close to finish.

Aborting when you are not ready

If you started a merge and realized you need to stop — maybe to ask a teammate or check something first — you can return the repository to its pre-merge state:

git merge --abort

This is safe to run at any point before the merge commit is created. After --abort, your working tree and index are restored to exactly what they were before you ran git merge.

Summary

Conflicts only happen on overlapping changes. The resolution loop is always the same: read the markers to understand both sides, edit the file to the correct final state, remove every marker, stage the file, and commit. Use git status to track remaining work and git merge --abort to escape cleanly if needed.

Quick check

0/3
Q1What does Git do to a conflicted file while waiting for you to resolve it?
Q2You have resolved all conflicts and staged every formerly-unmerged file. What is the correct next step?
Q3Your team's CI pipeline starts failing after a merge. You open the file and see a line that begins with seven equals signs in the middle of a function. What most likely happened?

Sign in to track your progress

Completed lessons, your XP, level, and streak save to your account — it's free and takes a few seconds.

Explore further

Cheat sheets

Related lessons

Skip to content