Resolving Merge Conflicts
A merge conflict happens when two branches change the same part of the same file in different ways, and Git can't know which version is right. It's a normal part of working with others, not an error. Git pauses the merge, marks the clashing lines, and waits for you to decide.
Causing a conflict
Sam changes the number of servings on a branch, while on main someone else changes the same line. (printf writes several lines at once; \n starts a new line.)
git switch -c bigger-batch printf 'Pancakes\nServes: 8\nMilk: 300 ml\nCook for 2 minutes each side.\n' > pancakes.txt git commit -am "Double the pancake batch" git switch main printf 'Pancakes\nServes: 2\nMilk: 300 ml\nCook for 2 minutes each side.\n' > pancakes.txt git commit -am "Make pancakes for two"
Switched to a new branch 'bigger-batch' [bigger-batch f793036] Double the pancake batch 1 file changed, 1 insertion(+), 1 deletion(-) Switched to branch 'main' [main ce25452] Make pancakes for two 1 file changed, 1 insertion(+), 1 deletion(-)
git merge bigger-batch
Auto-merging pancakes.txt CONFLICT (content): Merge conflict in pancakes.txt Automatic merge failed; fix conflicts and then commit the result.
Understanding the situation
The merge is paused halfway. git status explains what's going on and lists the files that need attention under "Unmerged paths":
git status
On branch main You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: pancakes.txt no changes added to commit (use "git add" and/or "git commit -a")
Look inside the file. Git has written both versions into it, separated by conflict markers:
cat pancakes.txt
Pancakes <<<<<<< HEAD Serves: 2 ======= Serves: 8 >>>>>>> bigger-batch Milk: 300 ml Cook for 2 minutes each side.
| Marker | Meaning |
|---|---|
<<<<<<< HEAD | Start of your version — the branch you're on (main) |
======= | Divider |
>>>>>>> bigger-batch | End of the incoming version from the branch being merged |
Only the conflicting lines are marked. Everything else in the file — and any other changes from both branches that didn't overlap — has already been merged automatically.
Resolving it
Edit the file to contain exactly what you want: one side, the other, or a combination. Then delete all three marker lines. Sam decides on 6 servings — and adjusts the milk to match:
printf 'Pancakes\nServes: 6\nMilk: 450 ml\nCook for 2 minutes each side.\n' > pancakes.txt
Mark the file as resolved by staging it, then commit to finish the merge:
git add pancakes.txt git status
On branch main All conflicts fixed but you are still merging. (use "git commit" to conclude merge) Changes to be committed: modified: pancakes.txt
git commit --no-edit git log --oneline --graph
[main 4689e87] Merge branch 'bigger-batch' * 4689e87 (HEAD -> main) Merge branch 'bigger-batch' |\ | * f793036 (bigger-batch) Double the pancake batch * | ce25452 Make pancakes for two |/ * 5370c83 Add pancake recipe
Before committing, double-check that no markers are left behind — searching the project for <<<<<<< is a good habit, and git diff --check warns about leftover markers too. If the project has tests, run them: a merge without textual conflicts can still combine two changes that don't work together.
Backing out
If a merge turns out messier than expected, cancel it. git merge --abort returns everything to how it was before you started the merge:
git merge weekend
Auto-merging pancakes.txt CONFLICT (content): Merge conflict in pancakes.txt Automatic merge failed; fix conflicts and then commit the result.
git merge --abort git status
On branch main nothing to commit, working tree clean
Taking one side completely
When you know one version is right for a whole file, you don't need to edit it by hand:
git checkout --ours pancakes.txt # keep the version from the current branch git checkout --theirs pancakes.txt # keep the version from the branch being merged git add pancakes.txt
To prefer one side for every conflict in the merge, use git merge -X ours branch or -X theirs. Use these with care — they silently discard the other side's changes to those lines.
Seeing the original too
Sometimes you need to know what the line looked like before either side changed it. Setting merge.conflictStyle to diff3 (or the tidier zdiff3 in Git 2.35+) adds a third section to each conflict showing the common ancestor's version:
git config merge.conflictStyle zdiff3 git merge weekend cat pancakes.txt
Auto-merging pancakes.txt CONFLICT (content): Merge conflict in pancakes.txt Automatic merge failed; fix conflicts and then commit the result. Pancakes Serves: 6 Milk: 450 ml <<<<<<< HEAD Cook for 90 seconds each side. ||||||| 4689e87 Cook for 2 minutes each side. ======= Cook for 3 minutes each side. >>>>>>> weekend
Now it's clear that both sides changed "2 minutes" — one to 3 minutes, the other to 90 seconds. Many people turn this on globally.
Tools
Most code editors highlight conflict markers and offer buttons such as "Accept Current", "Accept Incoming" and "Accept Both", and some have a three-pane merge editor. git mergetool opens each conflicted file in a merge tool you configure. They all do the same thing you did by hand: produce the final file, then you stage it.
Avoiding conflicts
- Keep branches short-lived and merge
maininto them often. - Make small, focused commits and avoid reformatting whole files alongside real changes.
- Agree on code formatting (an automatic formatter helps) so whitespace changes don't clash.
- Talk to teammates when you're both about to change the same area.
Try it yourself
Create a file with three lines and commit it. On a branch, change the middle line; on main, change the same line differently. Merge, resolve the conflict by combining both edits, and finish the merge. Then repeat and practise git merge --abort.