| name | conflict-resolver |
| description | Resolve git merge/rebase conflicts by analyzing git history, commit intent, and code context. Use when merge or rebase produces conflicts. |
Git Conflict Resolver
Resolve merge and rebase conflicts by understanding WHY both sides made their changes,
then choosing the right resolution based on intent — not just line-by-line diffing.
When to Use
git merge / git rebase / git cherry-pick produced conflicts
- PR can't merge due to conflicts
- Worktree rebase has conflicts after
git rebase origin/main
Phase 1: Understand the Conflict
Before touching any file, gather context:
git diff --name-only --diff-filter=U
git status --porcelain | grep "^[UAD][UAD]"
Detect the operation type
if git rev-parse --verify -q MERGE_HEAD >/dev/null 2>&1; then
echo "MERGE — ours=HEAD, theirs=MERGE_HEAD"
THEIRS="MERGE_HEAD"
elif git rev-parse --verify -q REBASE_HEAD >/dev/null 2>&1; then
echo "REBASE — ours=upstream (HEAD), theirs=your commits (REBASE_HEAD) — swapped!"
THEIRS="REBASE_HEAD"
elif git rev-parse --verify -q CHERRY_PICK_HEAD >/dev/null 2>&1; then
echo "CHERRY-PICK — ours=HEAD, theirs=CHERRY_PICK_HEAD"
THEIRS="CHERRY_PICK_HEAD"
fi
git log --oneline $THEIRS..HEAD -- <file>
git log --oneline HEAD..$THEIRS -- <file>
git blame HEAD -- <file> | head -30
git blame $THEIRS -- <file> | head -30
grep -n "<<<<<<\|======\|>>>>>>" <file>
⚠️ During rebase, --ours and --theirs are SWAPPED:
git merge: --ours = your branch, --theirs = incoming
git rebase: --ours = upstream (the branch you're rebasing onto), --theirs = your commits
Iron Law: understand BOTH sides before resolving. Never blindly accept one side.
Phase 2: Classify the Conflict
Classify each side's changes by intent:
| Type | Indicators | Resolution Priority |
|---|
| Security fix | "security", "vuln", "CVE" in commit message | Highest — always keep |
| Bug fix | "fix", "bug", "patch" in commit message; small targeted change | Highest — always keep |
| Refactor | "refactor", "cleanup", "rename"; no behavior change | Medium — preserve both if compatible |
| Feature | "feat", "add", "implement"; new functionality | Medium — merge carefully |
| Style | "style", "format", "lint"; whitespace/formatting only | Lowest — accept either side |
Phase 3: Resolve
Decision Framework
- Same intent, compatible changes → merge both (most common)
- Bug fix vs feature → bug fix wins, integrate feature around it
- Conflicting logic → prefer the more recent or more tested change
- Style/format conflicts → accept either, prefer consistency with surrounding code
- Deletions vs modifications → investigate why deleted; deletion is usually intentional
- Lock files (
package-lock.json, uv.lock, yarn.lock, pnpm-lock.yaml) → NEVER merge manually.
Resolve the manifest first (package.json, pyproject.toml, etc.), then regenerate:
rm -f uv.lock
uv lock
rm -f package-lock.json
npm install
rm -f yarn.lock
yarn install
The manifest defines WHAT you want. The lock file is generated FROM the manifest. Never pick a side for the lock file — just regenerate it.
Resolution Commands
git checkout --theirs <file>
git add <file>
git checkout --ours <file>
git add <file>
⚠️ During rebase, --ours/--theirs are swapped. If unsure, use git diff :2:<file> :3:<file> to compare stage 2 (ours) vs stage 3 (theirs) directly.
git add <file>
For Manual Resolution
- Read the ENTIRE conflict block — not just the markers
- Check what comes BEFORE and AFTER the conflict — context matters
- If both sides add imports → keep both (deduplicate)
- If both sides modify the same function → merge logic carefully, test
- If one side deletes code the other modifies → check git log to understand why
Phase 4: Verify
grep -rn "<<<<<<\|======\|>>>>>>" <resolved-files>
git diff --name-only --diff-filter=U
uv run python -c "import ast; ast.parse(open('<file>').read())"
npx tsc --noEmit
go build ./...
uv run pytest -q
Phase 5: Complete
git add <all-resolved-files>
git commit
git add <all-resolved-files>
git rebase --continue
Common Patterns
Import Conflicts
Both sides added different imports → keep all, deduplicate:
from module import foo, bar
from module import foo, baz
from module import bar, baz, foo
Function Modification Conflicts
Both sides changed the same function → merge logic:
- Read both versions completely
- Identify what each change does
- If independent changes → combine both
- If conflicting behavior → pick the one that matches current requirements
Config/YAML Conflicts
Both sides added different config entries → merge sections:
Anti-Patterns
| Don't | Why | Instead |
|---|
git checkout --ours . | Discards ALL incoming changes | Resolve file by file |
| Manually edit lock files | Corrupts dependency resolution | Regenerate from scratch |
| Skip git blame | Wrong intent, wrong resolution | Always check commit history |
| Resolve without understanding | Creates subtle bugs | Read both sides first |
| Accept AI's first suggestion blindly | AI often picks one side | Verify the merge makes sense |