How it works
The explanation, with examples you can run.
Make a conflict
git init -q -b main demo && cd demoprintf 'port = 8080\n' > app.conf && git add app.conf && git commit -q -m "Add config"git switch -q -c featureprintf 'port = 9090\n' > app.conf && git commit -q -am "Use 9090"git switch -q mainprintf 'port = 8000\n' > app.conf && git commit -q -am "Use 8000"git merge featureAuto-merging app.confCONFLICT (content): Merge conflict in app.confAutomatic merge failed; fix conflicts and then commit the result.The merge is paused, not failed. Look at what Git left you:
cat app.confgit status --shortgit ls-files --stage<<<<<<< HEADport = 8000=======port = 9090>>>>>>> featureUU app.conf100644 2bc054ac1ac9ba969571a07977ba7b834faa7f81 1 app.conf100644 fc6e07056afbbfe74c1514428e320de0312467f1 2 app.conf100644 3792a7b6aed34427e6bf21b15a1d8005b9f16375 3 app.confUU means unmerged on both sides. The index holds the base (stage 1), ours (stage 2, HEAD) and theirs (stage 3, feature). git show :1:app.conf prints any of them, and git checkout --ours app.conf or --theirs takes one side whole.
See the original too
The default markers don't show what the line was before either change. The zdiff3 style adds the base, which usually makes the right answer obvious:
git merge --abortgit -c merge.conflictStyle=zdiff3 merge feature > /dev/nullcat app.conf<<<<<<< HEADport = 8000||||||| 3221dfcport = 8080=======port = 9090>>>>>>> featureBoth sides changed 8080, so this is a real disagreement that needs a person. Set it for good with git config --global merge.conflictStyle zdiff3.
Resolve and finish
Write the result you want, remove every marker, stage it and commit:
printf 'port = 9090\n' > app.confgit add app.confgit commit -q --no-editgit log --oneline --graph* 5f7f472 Merge branch 'feature'|\ | * 32c5fbc Use 9090* | 4a59ec3 Use 8000|/ * 3221dfc Add configHabits that help
- Read both commits first.
git log --merge -p app.confshows the commits on each side that touched the file, so you resolve by intent, not by guessing. - Use a merge tool if you like one.
git mergetoolopens a configured tool (VS Code, IntelliJ, vimdiff) with all three versions. - Build and test before committing. Git only checks markers are gone. Code can merge without conflicts and still be broken, for example when one side renames a function the other side calls.
- In a rebase, "ours" is the base. Rebase replays your commits on top of the other branch, so
--oursis the branch you are rebasing onto. Resolve,git add, thengit rebase --continue; the same conflict may come back for each replayed commit. - Let Git remember.
git config --global rerere.enabled truerecords how you resolved a conflict and reapplies it when the same conflict appears again, handy for long rebases. - Keep branches short. The longer two branches stay apart, the more their changes overlap.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.