Merge conflicts are not failures — they are git refusing to guess. Two lines of history made incompatible claims about the same text, and a human has to pick. The craft is a repeatable method that keeps small conflicts small and large ones tractable.

Before you resolve: understand the collision #

The scene of the accident
$ git merge feature/toc
CONFLICT (content): Merge conflict in src/toc.js
$ git log --oneline main..feature/toc     # what they bring
$ git log --oneline feature/toc..main     # what main gained meanwhile

Thirty seconds reading both sides' recent commits usually explains why the conflict exists — and whether your change or theirs should win.

Reading and resolving #

The markers, named
<<<<<<< HEAD
timeout = 60          <- your branch's version
=======
timeout = 120         <- their version
>>>>>>> feature/toc

Resolve by rewriting the marked region to the correct result — which is one of:

  • Yours: their change is outdated (but check they did not fix something too).
  • Theirs: they superseded your approach.
  • A combination: both changes apply to different aspects that happen to share lines — most common in import blocks and config.
Side-taking shortcuts, then the honest edit
$ git checkout --ours src/toc.js     # take your whole file version
$ git checkout --theirs src/toc.js   # take theirs
$ git add src/toc.js                 # mark resolved

Side-taking is per-file and blunt; real conflicts are per-hunk and need editing. Both paths end in git add.

The loop #

  1. git status — the authoritative list of unresolved files.
  2. Resolve one file, run the tests for it, git add.
  3. Repeat until status is clean.
  4. git commit to conclude the merge (the message is pre-written).
  5. Diff the result against both parents — surprises live there.

Useful escape hatches #

WantCommand
Abort everything, retry latergit merge --abort
A conflicted file as it was before the mergegit checkout HEAD -- file
Every conflicted file listed with degreesgit diff --name-only --diff-filter=U
Skip this one commit entirely (rebase)git rebase --skip
Stop mid-rebase, keep progressgit rebase --quit... use --abort for clean exits

Conflicts during rebase work the same way with a different vocabulary: resolve, git add, then git rebase --continue instead of committing. The Git series continues.