Merge Conflict Resolution Checklist
A step-by-step playbook for resolving merge or rebase conflicts safely. Run the steps in order -- skipping ahead is how clean working trees get clobbered. Every step has an exit ramp (--abort) so you can back out at any point until the final commit.
How to Use This Checklist
- Treat each step as a checkpoint. Do not start step N+1 until step N is green.
- If anything looks wrong (uncommitted work, surprise files, an unfamiliar branch), STOP and run step 18 (
--abort). - Most conflicts are resolved in steps 8-13. Steps 1-7 prevent conflicts; steps 14-20 verify the resolution.
Phase 1: Prepare (Steps 1-5)
Do all of these BEFORE you start the merge or rebase. Skipping prep is the #1 cause of "I lost my changes" disasters.
1. Make sure your working tree is clean
git statusIf anything is staged or modified, commit it, stash it, or discard it. Never start a merge with a dirty tree -- conflicts will mix your in-progress work with the merge resolution and you will not be able to tell them apart.
# Stash if you want to keep work-in-progress
git stash push -u -m "wip before merging main"2. Confirm you are on the right branch
git branch --show-currentYou merge INTO the current branch. If you are about to run git merge main, you should be on your feature branch -- not on main itself.
3. Update both branches from the remote
git fetch origin
git pull --ff-only origin <your-branch>A conflict resolved against a stale main is wasted work -- the real conflicts are still ahead of you. --ff-only refuses to silently merge if your branch has diverged.
4. Decide: merge or rebase
| Situation | Use |
|---|---|
| Feature branch already pushed and shared | git merge main (preserves history) |
| Personal branch, not yet pushed (or you force-push your own branches) | git rebase main (linear history) |
| Pulling teammate's changes into your branch | git pull --rebase if you have local commits, plain git pull otherwise |
If you are unsure, use merge. It is harder to lose work with a merge.
5. Note your starting commit (your safety anchor)
git rev-parse HEAD
# write this SHA somewhere -- a sticky note, a scratch file, anywhereIf everything goes wrong, git reset --hard <that-sha> puts you back exactly where you started. git reflog works too, but a written-down SHA is faster under stress.
Phase 2: Trigger the Merge (Steps 6-7)
6. Run the merge or rebase command
# Merge approach
git merge main
# OR rebase approach
git rebase mainIf there are no conflicts, you are done -- skip to step 19.
7. Read the output before doing anything else
Git prints exactly which files conflict and what kind of conflict each is (content vs. add/add vs. delete/modify). Read this list. Do not start opening files until you know how many conflicts you have and where they are.
git status
# Look for "Unmerged paths" -- that is your work list# Get a clean list of just the conflict files
git diff --name-only --diff-filter=UPhase 3: Understand Each Conflict (Steps 8-10)
Resolve the simplest conflicts first to shrink the surface area. Save the gnarly ones for last when you have momentum.
8. Open the first conflicted file and read the markers
Conflict markers look like this:
<<<<<<< HEAD
your version (the branch you are merging INTO)
=======
their version (the branch you are merging FROM)
>>>>>>> main
During a rebase, the labels are inverted: HEAD is the base branch you are rebasing onto, and the >>>>>>> side is your incoming commit. This catches everyone off guard at least once.
9. Look at both sides in context, not just the diff
# Show the full diff with both sides
git diff
# Or for one specific file
git diff -- path/to/file.ts
# See who wrote each side and why
git log --merge --oneline -- path/to/file.ts
git log -p HEAD..MERGE_HEAD -- path/to/file.tsKnowing why each side made a change -- not just what it changed -- is the difference between a real resolution and a guess that compiles.
10. Decide the resolution strategy for this file
Pick one before editing:
| Strategy | When |
|---|---|
| Keep ours | Their change is irrelevant to your branch |
| Keep theirs | Your change is now redundant (e.g., they did the same thing) |
| Combine both | Both changes are needed and do not collide semantically |
| Rewrite | Both sides are wrong now, given the other side exists |
# Take one side wholesale
git checkout --ours path/to/file.ts
git checkout --theirs path/to/file.tsPhase 4: Edit and Stage (Steps 11-13)
11. Edit the file: remove the markers, write the resolution
Delete every <<<<<<<, =======, and >>>>>>> line. The file should compile and read naturally as if it had never been conflicted.
A common mistake is leaving stray markers in untouched parts of the file. Search for them:
grep -rn '<<<<<<<\|=======\|>>>>>>>' .12. Run the file through its tooling
For each resolved file, run whatever check is fast and local:
# Type check
npx tsc --noEmit
# Format
npx prettier --write path/to/file.ts
# Lint
npx eslint path/to/file.tsIf a Server Component and a Client Component both import each other after merging, fix the boundary now -- not after staging.
13. Stage the resolved file
git add path/to/file.tsFor a rebase, git add does NOT auto-progress -- you still need step 16. For a merge, staging all conflicts puts you ready to commit.
Repeat steps 8-13 for every file in git status.
Phase 5: Verify (Steps 14-17)
14. Confirm zero conflicts remain
git statusEvery file under "Unmerged paths" must be gone. If git diff --name-only --diff-filter=U returns nothing, you are clean.
15. Run the full build and test suite
npm run build
npm run typecheck
npm testA merge that compiles individual files but breaks the build is the most common bad-merge outcome. Catch it now, not in CI.
16. Continue the rebase (rebase only)
git rebase --continueIf more conflicts appear, you are now resolving the NEXT commit's conflicts. Loop back to step 8 for each.
17. Sanity-check the final diff
# For a merge: what will the merge commit contain?
git diff HEAD
# For a rebase: how does my branch differ from before?
git range-diff <starting-sha>..ORIG_HEAD <starting-sha>..HEADIf the diff has files you did not touch or expect, something went wrong. Stop and investigate before committing.
Phase 6: Finish or Bail Out (Steps 18-20)
18. Bail-out command if anything feels wrong
At ANY point before the final commit, you can return to step 1's state:
git merge --abort
git rebase --abortIf you already committed and need to undo:
git reset --hard <starting-sha-from-step-5>There is no shame in aborting. A clean re-attempt is faster than untangling a half-broken merge.
19. Complete the merge or rebase
# Merge: commit the merge with the auto-generated message (or write your own)
git commit
# Rebase: should already be done after the final --continueFor a merge commit, write a body that explains what the conflicts were and how you resolved them. Future-you will thank you during a bisect.
20. Push -- carefully
# Merge: regular push is fine
git push
# Rebase: force-push, but ONLY to your own branches and ONLY with --force-with-lease
git push --force-with-lease--force-with-lease refuses the push if someone else committed to the remote branch since you last fetched -- it is the difference between rewriting your own history and overwriting a teammate's commit. Never --force (without -with-lease) on a shared branch.
Quick Reference: Bail-Out Cheatsheet
| You are at... | Get out with... |
|---|---|
| Mid-merge, conflicts unresolved | git merge --abort |
| Mid-rebase, conflicts unresolved | git rebase --abort |
| Already committed the merge, regret it | git reset --hard ORIG_HEAD |
| Already pushed a bad merge | git revert -m 1 <merge-sha> (do NOT force-push to undo) |
| Lost track entirely | git reflog -- find the SHA from before, then git reset --hard <sha> |
Common Mistakes
- Resolving conflicts on a stale base. Always pull
mainfirst (step 3). Resolving against last week'smainmeans doing the work twice. - Mixing your in-progress work into the resolution. A dirty tree at the start of a merge is a guaranteed bug. Stash first (step 1).
- Confusing "ours" and "theirs" during a rebase. They flip. When in doubt, look at
git logto confirm which commit is which. - Committing with markers still in the file. Always grep for
<<<<<<<before staging. - Force-pushing a shared branch. Use
--force-with-lease, and never onmain.