Resolving Conflicts
Date: 2026-08-17
A conflict is git declining to guess which of two changes to the same lines you meant. It’s not an error — it’s the one moment git refuses to make a decision on your behalf, and most conflict pain comes from the branch having lived too long rather than from the merge itself.
A merge conflict occurs when two branches change the same region of a file, or when one deletes what the other modified, and git cannot determine the intended result.
Git resolves everything it can automatically. A conflict means genuine ambiguity — two humans made incompatible decisions about the same lines.
Reading the markers
<<<<<<< HEAD
const timeout = 3000
=======
const timeout = 5000
>>>>>>> feature/slow-network
- Between
<<<<<<<and=======— the version on the branch you’re merging into (HEAD, usually yours) - Between
=======and>>>>>>>— the version coming in
In a rebase these are the other way round, because your commits are being replayed onto the other branch — so “ours” is the branch you’re rebasing onto. This is the single most common source of resolving a conflict backwards.
The resolution isn’t always one side
git checkout --ours file.js # keep yours
git checkout --theirs file.js # keep theirsBoth of those are usually wrong. A conflict means two people had reasons; the correct result frequently combines them, or is a third thing neither wrote.
// theirs: 5000 for slow networks
// yours: 3000 for responsiveness
// actual answer:
const timeout = navigator.connection?.saveData
? 8000
: 3000Read both sides and understand why each was written before choosing. If you can’t tell, ask the person — a two-minute conversation beats a silently wrong resolution.
The commands
git status # which files conflict
git diff # what the conflict is
git mergetool # a three-way view
git add file.js # mark resolved
git merge --continue # or rebase --continue
git merge --abort # back out entirely
git rebase --abort--abort is always available until you finish. There is no state you can’t back out of, which is worth knowing before panic sets in.
Three-way is better than two
Most tools show yours, theirs, and the result. Enable the base as well:
git config --global merge.conflictstyle zdiff3<<<<<<< HEAD
const timeout = 3000
||||||| base
const timeout = 1000
=======
const timeout = 5000
>>>>>>> feature
The base shows what both sides started from, which usually makes the intent obvious — here, both sides raised the timeout from 1000, so the disagreement is about how much, not about direction.
Reuse a resolution
If you resolve the same conflict repeatedly — common when rebasing a long branch — git can remember:
git config --global rerere.enabled truererere — reuse recorded resolution — records how you resolved a conflict and replays it automatically next time the same one appears. Genuinely useful on long-lived branches, and almost nobody has it on.
Preventing them
Most conflict pain is preventable, and none of the prevention is about git:
- Short branches. The dominant factor by a distance — Branching Strategies
- Integrate
mainfrequently rather than at the end - Small pull requests, reviewed and merged quickly — Code Review
- Agree ownership boundaries. Two people rewriting the same module simultaneously is a planning failure that presents as a git problem
- Formatters, agreed and automated. A large share of conflicts are whitespace and style, and they vanish once formatting is deterministic — Formatting
- Avoid mass reformatting in a branch. It conflicts with everything, and it hides real changes in the diff
After resolving
Always build and test after a conflict resolution. A resolution that merges cleanly at the text level can be semantically broken — you kept both sides of a rename, or resolved to code calling a function the other side deleted.
Git checks lines, not meaning, and the merge that compiles and fails at runtime is the characteristic bad outcome here.