What you will achieve
You will create a merge conflict deliberately, walk through the resolution, and learn the tools and patterns that make conflicts non-scary. Conflicts are not errors; they are Git asking you a question.
Step 1: set up a sandbox
mkdir conflict-tutorial && cd conflict-tutorial
git init
cat > recipe.txt <<'EOF'
Tomato Sauce Recipe
Ingredients:
- 1 onion, chopped
- 2 cloves garlic
- 1 can tomatoes
EOF
git add recipe.txt
git commit -m "Initial recipe"
Step 2: create two diverging branches
git checkout -b add-basil
sed -i.bak 's/2 cloves garlic/2 cloves garlic\n- handful of basil/' recipe.txt && rm recipe.txt.bak
git commit -am "Add basil"
git checkout -b add-oregano main
sed -i.bak 's/2 cloves garlic/2 cloves garlic\n- pinch of oregano/' recipe.txt && rm recipe.txt.bak
git commit -am "Add oregano"
Step 3: trigger the conflict
git checkout main
git merge add-basil
git merge add-oregano
Git prints:
CONFLICT (content): Merge conflict in recipe.txt
Automatic merge failed; fix conflicts and then commit the result.
Step 4: read the conflict markers
Open recipe.txt:
<<<<<<< HEAD
- handful of basil
=======
- pinch of oregano
>>>>>>> add-oregano
The block between <<< and === is your current branch. Between === and >>> is the incoming branch. Decide what should be in the file.
Step 5: resolve
Edit the file to the desired final state - in this case, both:
- 2 cloves garlic
- handful of basil
- pinch of oregano
- 1 can tomatoes
Remove all conflict markers entirely.
Step 6: stage and complete the merge
git add recipe.txt
git status # confirm "All conflicts fixed"
git merge --continue
# or:
git commit # opens editor with merge message
Tools that help
git mergetool # opens configured visual merge tool
git config --global merge.tool vimdiff # or kdiff3, meld, beyond compare
Modern editors (VS Code, JetBrains, Sublime Merge) provide three-pane merge interfaces that make conflicts much easier than text-only.
Aborting
git merge --abort
This returns the working tree and index to the pre-merge state. Useful when you realise you started the merge on the wrong branch.
Common patterns
- Take one side wholesale:
git checkout --ours fileorgit checkout --theirs file. - Take both: combine manually or use
git merge -X theirs/-X oursas a strategy hint. - Restart the merge:
git merge --abortthen re-merge after fixing the source branches.
Inspecting before resolving
git diff # show the conflict context
git log --merge -p <file> # commits on both sides that touched this file
git show :1:<file> # the merge base version
git show :2:<file> # the "ours" version
git show :3:<file> # the "theirs" version
Rerere for repeated conflicts
git config --global rerere.enabled true
"Reuse recorded resolution" remembers how you resolved a particular conflict and applies the same resolution next time it appears - invaluable on long-running feature branches.
The mental model
A conflict means Git could not auto-merge a region because both sides changed it. The resolution is always: decide the final state, edit the file, stage, commit. With practice, conflicts are minutes of work, not hours of dread.