From f07cff591ca59886c8a476af59d81973c03459c2 Mon Sep 17 00:00:00 2001 From: Jakob Heuser Date: Sat, 11 Jul 2026 00:32:56 -0700 Subject: [PATCH 1/2] docs: Harden stacked-PR recovery to resolve merge SHA from the PR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The base-branch restore step used `git rev-parse origin/main^2`, which only yields the child's merge-commit second parent while that merge is still main's tip. Once any later PR merges (or the tip is a squash/rebase commit), origin/main^2 points at the wrong SHA and restores the wrong branch head. Resolve the merge commit from the closed PR itself via `gh pr view --json mergeCommit`, then take its second parent — correct regardless of what has landed on main since. Surfaced by Copilot on the taskless/public port of this runbook (public#9); fixing it upstream here so it flows to public and taskless/taskless. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 17dd456..4ffb94a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,8 +66,11 @@ Stacked branches share commits (each child contains its ancestors). Prefer expli ### Recovery if a child PR gets closed by base-branch deletion -1. Restore the deleted base branch ref at the merge commit's second parent: - `gh api --method POST repos///git/refs -f ref=refs/heads/ -f sha=$(git rev-parse origin/main^2)` +1. Restore the deleted base branch ref at the child's merge commit's second parent. Resolve the merge commit from the closed PR itself — do **not** use `origin/main^2`, which is only that second parent while the merge is still `main`'s tip (any later merge, or a squash/rebase tip, makes it the wrong SHA): + ```bash + MERGE_SHA=$(gh pr view --repo / --json mergeCommit --jq .mergeCommit.oid) + gh api --method POST repos///git/refs -f ref=refs/heads/ -f sha=$(git rev-parse "$MERGE_SHA^2") + ``` 2. Reopen the child via **REST** (GraphQL `gh pr reopen` fails on the Projects-classic deprecation): `gh api --method PATCH repos///pulls/ -f state=open` 3. Retarget it: `gh pr edit --base main` (only works once it's open). From 89c15d58762473e463a91873f2d1152f51ea39fb Mon Sep 17 00:00:00 2001 From: Jakob Heuser Date: Sat, 11 Jul 2026 00:43:37 -0700 Subject: [PATCH 2/2] docs: Disambiguate parent vs child PR in stack recovery step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The restore step resolved the merge commit from , the same placeholder used for the child PR in steps 2-3. But the child is the PR that gets *closed* by the base-branch deletion — it is unmerged, so its mergeCommit is null and git rev-parse "$MERGE_SHA^2" would fail. The merge commit belongs to the parent PR (merged with --delete-branch); its second parent is the deleted base branch's pre-merge tip. Split the placeholders into (merged) and (closed), and add a lead-in naming the two PRs so the step reads unambiguously. Caught by Copilot review on this PR. Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 4ffb94a..f59d659 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -66,14 +66,16 @@ Stacked branches share commits (each child contains its ancestors). Prefer expli ### Recovery if a child PR gets closed by base-branch deletion -1. Restore the deleted base branch ref at the child's merge commit's second parent. Resolve the merge commit from the closed PR itself — do **not** use `origin/main^2`, which is only that second parent while the merge is still `main`'s tip (any later merge, or a squash/rebase tip, makes it the wrong SHA): +This happens when the **parent** PR is merged with `--delete-branch`: deleting the parent's head branch (which is the child's base) closes the **child** PR. Two PRs are involved — the merged parent (``) and the closed child (``); `` is the deleted base, i.e. the parent's head branch. + +1. Restore the deleted base branch ref at the **parent** merge commit's second parent (the deleted branch's pre-merge tip). Resolve the merge commit from `` — the PR that actually merged — **not** the closed child (it's unmerged, so its `mergeCommit` is `null` and `git rev-parse` would fail), and **not** `origin/main^2` (only that second parent while the parent merge is still `main`'s tip; any later merge, or a squash/rebase tip, makes it the wrong SHA): ```bash - MERGE_SHA=$(gh pr view --repo / --json mergeCommit --jq .mergeCommit.oid) + MERGE_SHA=$(gh pr view --repo / --json mergeCommit --jq .mergeCommit.oid) gh api --method POST repos///git/refs -f ref=refs/heads/ -f sha=$(git rev-parse "$MERGE_SHA^2") ``` 2. Reopen the child via **REST** (GraphQL `gh pr reopen` fails on the Projects-classic deprecation): - `gh api --method PATCH repos///pulls/ -f state=open` -3. Retarget it: `gh pr edit --base main` (only works once it's open). + `gh api --method PATCH repos///pulls/ -f state=open` +3. Retarget it: `gh pr edit --base main` (only works once it's open). ### Other gotchas