Skip to content

Conflict Resolution

Strategies for resolving merge conflicts thoughtfully, preserving the intent of all commits involved.

When to use

Use these strategies when a merge or rebase produces conflicts — the goal is always to resolve them while retaining the intent from all conflicting versions:

StrategyUse when
Simple mergeIntent is clear from the conflict markers alone
Patch replayConflicts are widespread; a clean slate preserves intent best
Commit replayConflicts are isolated; per-commit replay preserves intent best

The pattern

General principles

  1. Understand before resolving — Don't just pick one side
  2. Preserve intent — Honor what each commit was trying to accomplish
  3. Test after resolution — Verify the merged result actually works
  4. Clear commit messages — Explain how you preserved both sides

Simple merge

Deal with merge conflicts thoughtfully — think hard about what's happening. Look at all relevant git history and retain the intent of every commit.

Approach

  1. First, understand what's happening:

    • Run git status to see which files are conflicted
    • Run git log --merge --oneline to see all commits involved in the conflict
    • Figure out which branches are being merged and why
  2. Think hard about the history:

    • Look at all relevant git history for each conflicted file
    • Run git log -p --merge <file> to see the actual changes in detail
    • Use git show <commit> to deeply understand specific commits
    • Read every commit message to understand what the developer was trying to achieve
  3. Retain the intent of every commit:

    • Don't just pick one side or the other
    • Understand what each commit was trying to accomplish
    • Think about why each change was made
    • Consider how different changes relate to each other
  4. Deal with the conflict thoughtfully:

    • Open each conflicted file and carefully examine the conflict markers
    • Think hard about how to preserve the intent of both sides
    • Combine changes in a way that retains what every commit was trying to do
    • Don't take shortcuts — make sure the resolution honors all the work that went into both branches
    • Remove conflict markers only after you're confident in your resolution
  5. Make sure you got it right:

    • Stage resolved files with git add
    • Test that your resolution actually works
    • Write a clear commit message that explains how you preserved the intent of all commits

Remember: This isn't about speed. It's about being thoughtful and retaining the intent of every single commit. Take the time to think hard about what each developer was trying to accomplish.

Quick reference

sh
git status                    # See conflicted files
git log --merge --oneline     # See commits involved
git log -p --merge <file>     # See changes in detail

Patch replay

A robust, non-interactive pattern to get a conflicted branch into a mergeable state with main by converting changes to a patch, resetting to main, and manually re-applying changes. Best when the branch has conflicts with main, squashing into one commit is acceptable, and standard conflict resolution is error-prone.

Steps

Phase 1: Create a "To-Do List" (The Patch)

Save all unique work into a single patch file:

sh
git fetch origin
git diff origin/main...HEAD > /tmp/my_changes.patch

if [ ! -s /tmp/my_changes.patch ]; then
  echo "No unique changes detected. Stopping."
  exit 0
fi

Phase 2: Create a Clean Slate

Reset the branch to be identical to main:

sh
git reset --hard origin/main

Phase 3: Thoughtfully Re-Apply Work

This is the most critical step. Read the patch file as instructions and manually edit the code. Do not use git apply, which will fail.

Provide progress visibility:

  • "Found 12 change hunks across 5 files to apply"
  • "Processing file 2 of 5: src/utils.js (3 hunks)"
  • "Applied authentication check to line 45"

Instructions:

  1. Open and read /tmp/my_changes.patch
  2. Go through each hunk (change block) systematically
  3. For each hunk:
    • Identify the target file
    • Open that file (now the main version)
    • Find the correct line number and context
    • Analyze the code — main may differ from the patch's context
    • Manually edit to apply the intent of the patch

Minimize approval prompts: Use built-in tools (Read, Edit, Grep) instead of shell commands (cat, sed, grep).

Phase 4: Finalize and Clean Up

sh
git add .
git commit -m "Re-apply changes on latest main"
rm /tmp/my_changes.patch

Checks

  • Verify merge is clean by running git merge --no-commit --no-ff origin/main && git merge --abort
  • All tests must pass
  • Review the final commit before merging

What not to do

  • DO NOT use git rebase -i — stateful, will fail
  • DO NOT parse merge conflict markers — error-prone
  • DO NOT use git apply /tmp/my_changes.patch — not conflict-aware
  • DO NOT apply hunks silently — users need visibility

Commit replay

A robust pattern for resolving merge conflicts by replaying each commit individually onto main, isolating conflicts to single commits while preserving commit history. Best when the branch has diverged from main, commit history is valuable and should be preserved, and conflicts are likely isolated to specific commits.

Steps

Phase 1: Setup

sh
git fetch origin
CONFLICT_BRANCH=$(git branch --show-current)

# Create new branch from latest main
git checkout -b ${CONFLICT_BRANCH}-fix origin/main

# Get commits to replay (oldest-first)
git rev-list origin/main..${CONFLICT_BRANCH} --reverse \
> /tmp/commits_to_replay.txt

COUNT=$(wc -l < /tmp/commits_to_replay.txt)
echo "Setup complete. Found $COUNT commits to replay."

Phase 2: The Replay Loop

For each commit, process sequentially with clear progress visibility:

  • "Processing commit 3 of 15: fixing auth bug"

Step 2a: Attempt automatic application

sh
sha=$(head -n1 /tmp/commits_to_replay.txt)
COMMIT_MSG=$(git log -1 --format=%B $sha)
git format-patch -1 $sha --stdout \
> /tmp/current_commit.patch

if git am /tmp/current_commit.patch 2>/dev/null; then
  echo "Commit $sha applied cleanly"
else
  echo "Conflict detected for commit $sha"
  git am --abort
fi

Step 2b: If conflict, resolve manually

  1. Read the patch to understand what changed
  2. Examine current state of affected files
  3. Re-implement the logical changes in the new context
  4. Apply the intent, not literal text replacement
sh
git add -A
git commit -m "$COMMIT_MSG"
echo "Conflict resolved for $sha"

Use built-in tools: Prefer Read, Edit, Grep over cat, sed, grep.

Step 2c: Continue until done

Remove processed commit and repeat until /tmp/commits_to_replay.txt is empty.

Phase 3: Finalize and Replace

sh
FIX_BRANCH=$(git branch --show-current)
CONFLICT_BRANCH=${FIX_BRANCH%-fix}

# Preserve original as backup
git branch -m ${CONFLICT_BRANCH} \
  ${CONFLICT_BRANCH}-conflict
git branch -m ${FIX_BRANCH} ${CONFLICT_BRANCH}
git checkout ${CONFLICT_BRANCH}

rm /tmp/commits_to_replay.txt
echo "Branch successfully rebased on main."

Checks

  • Verify merge is clean by running git merge --no-commit --no-ff origin/main && git merge --abort
  • Same number of commits as original branch
  • All tests must pass
  • Review final branch before merging

What not to do

  • DO NOT use git rebase -i — interactive commands fail
  • DO NOT use git cherry-pick --continue — stateful, brittle
  • DO NOT parse merge conflict markers — error-prone
  • DO NOT process commits without progress updates

Trade-offs

StrategyProsCons
Simple mergePreserves full historyComplex with many conflicts
Patch replayClean reset, simple resultLoses individual commits
Commit replayPreserves individual commitsSlower, more manual effort