A conflict is not an error — it's Git refusing to guess which of two edits wins. The fix is a text edit plus two commands. Escape hatch first, in case you're mid-panic: git merge --abort puts everything back.
git status
# "Unmerged paths:" lists the conflicted files:
# both modified: config.py
<<<<<<< HEAD
timeout = 30 # ← YOUR version (current branch)
=======
timeout = 60 # ← THEIR version (incoming branch)
>>>>>>> feature-x
# everything between the markers is the disputed zone.
# the rest of the file is already merged fine.
# keep yours, keep theirs, or write something new:
timeout = 60
# what must be true when you're done:
# 1. the code is what you actually want
# 2. no <<<<<<<, =======, >>>>>>> anywhere in the file
git add config.py
git commit # git pre-fills the merge message — save & close
# done. the merge commit ties both histories together.
# the whole file, my version:
git checkout --ours config.py && git add config.py
# the whole file, their version:
git checkout --theirs config.py && git add config.py
# great for lock files (package-lock.json etc.) — often the
# right answer is "take either side, then re-run the install".
<<<<<<< — search the project for <<<<<<< before committing any merge. 2. Resolving in a rush by picking a side blindly. The markers show what changed but not why — when both edits look intentional, ask the other author. Two minutes of Slack beats re-breaking their fix.
git rebase --continue (not commit), and the escape hatch is git rebase --abort. "Ours/theirs" are swapped during a rebase — read the marker labels, not your assumptions.
git pull often # small frequent merges beat giant rare ones
# keep branches short-lived (days, not months)
# don't reformat whole files in the same commit as logic changes
# (formatting-only diffs are conflict factories)