Get back to a known-good baseline on the default branch so the next task starts clean.
Resolve the default branch the same way /webdev:new-branch does (.claude/webdev.json
"defaultBranch" first — a pin beats detection — then origin/HEAD, falling back to
main/master). Call it <base>.
-
Check working tree state
git status --short
If non-empty (uncommitted, staged, or untracked), surface what's there and ask before
continuing. Do not silently stash or discard.
-
Note the starting branch and verify its PR status
git branch --show-current
-
Switch to base and fetch with prune
git checkout <base>
git fetch --prune
--prune removes remote-tracking refs for branches deleted on the remote after merge.
-
Pull latest base (fast-forward only)
git pull --ff-only
If the pull refuses to fast-forward, stop and surface it — the base should never have local
commits ahead of origin. Plain git pull would silently merge, defeating the purpose.
-
Identify safe-to-delete merged local branches
git branch --merged <base>
--merged only checks reachability — a tip can be in the base's history without its PR ever
being merged (cherry-picks, manual rebases, never-PR'd branches). Reachability is necessary
but not sufficient. For each candidate, verify a merged PR exists:
gh pr list --state merged --head <branch-name> --json number,mergedAt --limit 1
- Branch + verified merged PR → safe to propose for deletion.
- Branch with no merged PR → leave alone; surface separately as "base-reachable tip but
unverified PR status — not proposing deletion."
Filter out <base> itself unconditionally.
-
Confirm before deleting
List stale branches with short context (last commit subject + age) and ask for confirmation
before deleting. Default to a single confirm-all prompt.
git branch -d <branch-name>
Use -d (safe), never -D. If -d refuses, the branch isn't actually merged — surface it.
Squash-merge exception: GitHub's squash-merge default produces branches whose tip is NOT
reachable from base even after merge, so --merged won't list them and -d refuses
("not fully merged"). When gh pr list --state merged --head <branch> returns a merged PR
but -d refuses, verify the SHA before offering -D (--head matches by branch name
only, so a reused name could match an unrelated older merged PR):
pr_head_oid=$(gh pr list --state merged --head <branch> --json headRefOid --limit 1 | jq -r '.[0].headRefOid')
branch_tip=$(git rev-parse <branch>)
Only -D on explicit user confirmation AND a verified SHA match.
-
Report final state — see Output.