Concept · Merging & history
Three-way merges and conflicts
Git compares both sides with their common ancestor; a conflict is a line both sides changed.
Comparing only the two branch tips can't tell you who changed what. If a line differs, did you change it, or did they? A three-way merge adds a third version, the merge base: the most recent commit both branches share.
┌─ ours (main)
base ────┤
└─ theirs (feature)For each region of each file, Git compares both sides with the base:
| Ours vs base | Theirs vs base | Result |
|---|---|---|
| unchanged | unchanged | keep |
| changed | unchanged | take ours |
| unchanged | changed | take theirs |
| changed | changed, identically | take it |
| changed | changed, differently | conflict |
So most merges resolve automatically. A conflict means one specific thing: both sides changed the same region relative to the base, in different ways. Git can't know which one you want, or whether you want both.
Reading conflict markers
Turn on the base section. It shows what the code looked like before either change, which is often the key to resolving correctly:
git config --global merge.conflictStyle zdiff3<<<<<<< HEAD
const timeout = 5_000
||||||| base
const timeout = 3_000
=======
const timeoutMs = 3_000
>>>>>>> featureHere one side changed the value and the other renamed the variable. Neither side's version is right on its own. The correct resolution keeps both changes: const timeoutMs = 5_000.
Resolving
git statuslists the conflicted files.- Edit each one to the correct combined result, and remove the markers.
- Build and run the tests. A merge without conflicts can still be wrong. If one side renamed a function and the other added a call to the old name, both changes apply cleanly and the result doesn't compile.
git addthe files, thengit commit(orgit rebase --continue).
git merge --abort gets you back to the state before the merge. git rerere remembers how you resolved a conflict and reapplies it if the same conflict comes back, which helps with long-running branches.
Fewer conflicts
Conflicts grow with how long branches diverge and how many people edit the same lines. Small, short-lived branches merged often (trunk-based development) avoid most of them. Moving code and changing it in the same commit is a reliable way to create them.
See fast-forward vs merge commits for what's recorded after the merge.