Resolve PR Merge Conflicts
Rebase-only. Never a merge commit. A PR that conflicts with its base is fixed by replaying this branch's commits on top of the updated base (
git rebase), thengit push --force-with-lease.git merge <base>,git pullwithout--rebase, and any move that lands a merge commit on the branch are forbidden — the goal is linear history. When a rebase gets hard, the only escape isgit rebase --abort, never a merge. Plaingit push --forceis also forbidden; always--force-with-lease.
Asking the user: where a step says "ask the user", use the platform's blocking question tool (fall back to a question in chat when the tool is unavailable).
Context
In Claude Code the labeled sections below are pre-populated — use them directly. On other platforms run the fallback block.
Current branch:
!git branch --show-current
Working tree + in-progress state:
!git status
Remote default branch:
!git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo 'DEFAULT_BRANCH_UNRESOLVED'
PR state:
!gh pr view --json url,title,state,baseRefName,mergeable 2>/dev/null || echo 'NO_OPEN_PR'
Context fallback
printf '=== BRANCH ===\n'; git branch --show-current; printf '\n=== STATUS ===\n'; git status; printf '\n=== DEFAULT_BRANCH ===\n'; git rev-parse --abbrev-ref origin/HEAD 2>/dev/null || echo 'DEFAULT_BRANCH_UNRESOLVED'; printf '\n=== PR ===\n'; gh pr view --json url,title,state,baseRefName,mergeable 2>/dev/null || echo 'NO_OPEN_PR'
Step 1: Preflight
Resolve the base branch from the PR's baseRefName. If there is no PR, use the default branch (strip the origin/ prefix; if it returned DEFAULT_BRANCH_UNRESOLVED or bare HEAD, try gh repo view --json defaultBranchRef --jq '.defaultBranchRef.name', else fall back to main).
Stop conditions — report and stop rather than improvise:
- On the base branch itself (not a feature branch) — nothing to rebase.
- A
mergeis already in progress (status shows "You have unmerged paths" from a merge, or aMERGE_HEADexists) — stop and show the user the current state. Ask whether to abort that merge and restart with a rebase. Never abort automatically; the in-progress resolution may contain user work. - A
rebaseis already in progress — you are resuming; skip to Step 3. - Dirty working tree with uncommitted changes — a rebase requires a clean tree. Ask the user whether to commit the changes first or
git stashthem (and reapply after). Do not proceed until clean.
Then fetch the latest base:
git fetch origin
If git merge-base --is-ancestor origin/<base> HEAD succeeds, the branch is already on top of the base — there is nothing to rebase. Report and stop.
Step 2: Rebase onto the base
git rebase origin/<base>
If it completes with no conflicts, go to Step 4.
Step 3: Resolve conflicts, then continue
For each conflicted file: open it, resolve every conflict marker by hand so the result is correct (keep both intents where both are needed — do not blindly take one side), then git add <file>. When all conflicts in the current step are staged:
git rebase --continue
Repeat for each replayed commit until the rebase finishes.
If a step is genuinely unresolvable, or the same conflicts keep recurring across commits, or you are not confident the resolution is correct — abort and re-approach:
git rebase --abort
--abort returns the branch to exactly where it started, losing nothing. From there, either retry (e.g. git rebase origin/<base> -X ..., or interactively drop/reorder) or ask the user how to resolve. Never resolve a hard rebase by merging.
Step 4: Force-push with lease
The rebase rewrote this branch's commits, so its history diverges from the remote. Push with lease so a teammate's concurrent push is not clobbered:
git push --force-with-lease
If it is rejected because the remote moved, git fetch origin and inspect what changed before re-attempting — do not fall back to plain --force.
Step 5: Verify and report
Confirm the branch is now on top of the base with linear history and no merge commit introduced:
git log --oneline --graph -15
git merge-base --is-ancestor origin/<base> HEAD && echo "on top of base"
The graph must be a straight line (no fork/merge nodes) and the ancestor check must pass. Report the branch, the base it was rebased onto, how many commits were replayed, and the PR URL. If a PR is open, note that it should now show no conflicts.