sdd-resolving-merge-conflicts
Use when a merge, rebase, or cherry-pick has conflicts that need resolution
SKILL.mdskills/sdd-resolving-merge-conflicts/SKILL.md
GitHubResolving Merge Conflicts
Overview
Core principle: Understand both sides before choosing. Preserve both intents where possible. Never invent behavior. Resolve rather than abort.
Announce at start: "I'm using the sdd-resolving-merge-conflicts skill to resolve these conflicts."
A conflict means two changes touched the same lines with different intents. Resolution merges two histories into one coherent result — not by picking a side, and not by redesigning.
Step 1: See the State
Know which operation you are inside before touching a hunk:
git status
git log --oneline --graph -20
git diff --name-only --diff-filter=U
List the conflicting files and hunks. Merge, rebase, and cherry-pick resume differently, so establish which one is in progress first.
Step 2: Find the Primary Sources
For each side of each conflict, understand why the change was made and what the original intent was:
- Read both sides' commits — merge:
git log --oneline --left-right HEAD...MERGE_HEAD; rebase:git show REBASE_HEAD(the commit currently being replayed) and the surrounding replay commits when their intent matters; cherry-pick:git show CHERRY_PICK_HEAD. - Follow the references: PRs, issues, specs, plan documents.
- If intent is not recoverable from the sources, ask your human partner — never guess from the diff alone.
Step 3: Resolve Each Hunk
- Preserve both intents where possible. Many conflicts are additive at the edges; both changes can coexist.
- Where incompatible, pick the side that serves the operation's stated goal and record the trade-off — what was dropped and why — in the merge commit message (for rebase or cherry-pick, in the PR or handoff).
- Never invent behavior. Conflict resolution is not a refactor and not an opportunity to fix unrelated code. If the resolution seems to require new behavior, that is a separate change after the operation completes.
- Resolve rather than abort.
--abortis not a convenience exit; it is correct only when the operation itself is wrong (wrong base, changed goal) or your human partner asks to back out — and the reason gets recorded and surfaced, not swallowed. - Remove every conflict marker;
git diff --checkflags leftover markers and whitespace errors in tracked changes.
Step 4: Run the Project's Checks
Discover the project's automated checks and run them — typically typecheck, then tests, then format. Fix what the resolution broke; when a failure's cause is not obvious, investigate before fixing.
git diff --check # leftover markers, whitespace
<typecheck> && <test> && <format --check>
A resolution that compiles but fails tests is not resolved. Preserve the failure output and investigate it with sdd-systematic-debugging — the cause may be the resolution, the updated base, or the environment. Correct the resolution only when the investigation shows it is the cause.
Step 5: Finish the Operation
Stage the resolved paths only — git add <resolved paths>, never -A blindly (the tree may hold unrelated work, generated files, or secrets) — then inspect the staged diff for markers and whitespace (git diff --cached --check) before completing:
- Merge:
git commit(orgit merge --continue). - Rebase:
git rebase --continue, repeating until every commit is rebased. Commits keep their own messages, so the trade-off lives in the PR or handoff. - Cherry-pick:
git cherry-pick --continue; same message rule as rebase.
Never leave a half-finished operation behind unannounced: finish it, or — if debugging is blocked — stop and report exactly where it stands (operation in progress, evidence preserved). Never commit a red resolution or guess it green.
Quick Reference
| Situation | Action |
|---|---|
| Conflict in progress | Identify merge/rebase/cherry-pick before resolving (Step 1) |
| Unclear why a side changed | Read commits, PRs, issues; ask if unrecoverable (Step 2) |
| Both changes compatible | Keep both (Step 3) |
| Incompatible intents | Pick by the operation's goal; record the trade-off (Step 3) |
| Tempted to fix something else | Don't — resolve only, then a separate change (Step 3) |
Tempted to --abort |
Not a convenience exit; abort only for a wrong operation/goal or at your human partner's request (Step 3) |
| Checks fail after resolving | Investigate with sdd-systematic-debugging; fix the resolution if it is the cause (Step 4) |
| Operation half-finished | Finish it; if debugging is blocked, report exactly where it stands (Step 5) |
Common Rationalizations
| Excuse | Reality |
|---|---|
| "Ours is newer — just take ours" | A conflict is a question about intent; newer isn't the same as correct, and dropping the other side's intent silently is how regressions land. |
| "I'll merge both sides into a cleaner design" | That is a redesign smuggled into a merge. Resolve first; improve later in its own change. |
"--abort is the safe move" |
Abort restores the pre-operation state — it doesn't lose either side's committed history — but it discards the context you just gathered and defers the work. Resolve; abort only when the operation itself is wrong or your human partner asks, and record why. |
| "It compiles, so the merge is fine" | Compiling proves nothing about the paired intent. Run the project's checks. |
| "I'll finish the rebase later" | Half-finished operations are inherited by a context with none of yours. Finish now. |
| "That post-merge test failure is flaky" | Don't name a cause before investigating — preserve the output and follow Step 4; it may be the resolution, the updated base, or the environment. |