docs: fix review findings in the stacked-PR merge skill

Codex review caught three procedure defects: the dependent check used
bare 'gh pr list', whose default pagination can hide an open dependent
and make branch deletion look safe (now --state open --limit 1000); the
refresh step merged local master, which 'gh pr merge' leaves stale (now
fetch and merge origin/master); and the quick checklist omitted pushing
the dependent after the local merge.
This commit is contained in:
Tianyi Cui
2026-07-06 00:46:22 +08:00
parent bb4cc0ff60
commit dd44402871
2 changed files with 8 additions and 8 deletions

View File

@@ -19,10 +19,10 @@ Given `A ← B ← C` landing on `master`:
2. **Retarget PR B, refresh it, then merge it — keeping its branch.** 2. **Retarget PR B, refresh it, then merge it — keeping its branch.**
- `gh pr edit B --base master` (now that A is in master, B's base becomes master). - `gh pr edit B --base master` (now that A is in master, B's base becomes master).
- Merge the new master *into* branch B (check out B, `git merge master`, resolve any conflicts here, push). This makes B current and surfaces conflicts in the working branch where they can be tested — not as a surprise at the GitHub merge. - Merge the new master *into* branch B: check out B, `git fetch origin`, `git merge origin/master` — merge `origin/master`, not local `master`, because `gh pr merge` updated only GitHub and the local branch is stale — resolve any conflicts here, and push. This makes B current and surfaces conflicts in the working branch where they can be tested — not as a surprise at the GitHub merge.
- `gh pr merge B --merge` — still no `--delete-branch` (PR C bases on branch B). - `gh pr merge B --merge` — still no `--delete-branch` (PR C bases on branch B).
3. **Retarget PR C, refresh it, then merge it — keeping its branch.** Same steps: `gh pr edit C --base master`, merge new master into branch C and resolve conflicts there, then `gh pr merge C --merge` without `--delete-branch`. 3. **Retarget PR C, refresh it, then merge it — keeping its branch.** Same steps: `gh pr edit C --base master`, fetch and merge `origin/master` into branch C, resolve conflicts there and push, then `gh pr merge C --merge` without `--delete-branch`.
4. **Only after every PR (A, B, C) is merged, delete the branches** — local and remote, for all of A, B, C. 4. **Only after every PR (A, B, C) is merged, delete the branches** — local and remote, for all of A, B, C.
@@ -35,18 +35,18 @@ Each retarget step merges the freshly-updated master back into the dependent bra
Before *any* branch delete, confirm nothing still depends on it: Before *any* branch delete, confirm nothing still depends on it:
```sh ```sh
gh pr list --json number,baseRefName gh pr list --state open --limit 1000 --json number,baseRefName
``` ```
If any open PR's `baseRefName` is a branch you're about to delete, **do not delete it** — that PR will auto-close. Default to merging without `--delete-branch` throughout, and do the deletions as a separate final pass once the list shows no open dependents. The explicit `--limit` matters: without it the list is paginated, and a dependent past the first page would make deletion look safe when it is not. If any open PR's `baseRefName` is a branch you're about to delete, **do not delete it** — that PR will auto-close. Default to merging without `--delete-branch` throughout, and do the deletions as a separate final pass once the list shows no open dependents.
## Longer chains ## Longer chains
The pattern extends to any depth. For `A ← B ← C ← D ← …`, walk the stack from the bottom up: merge the lowest, then for each next link retarget to master, merge master into it, merge the PR — always without deleting — and only sweep up all the branches at the very end. The invariant never changes: **a branch may be deleted only when no open PR bases on it.** The pattern extends to any depth. For `A ← B ← C ← D ← …`, walk the stack from the bottom up: merge the lowest, then for each next link retarget to master, fetch and merge `origin/master` into it, merge the PR — always without deleting — and only sweep up all the branches at the very end. The invariant never changes: **a branch may be deleted only when no open PR bases on it.**
## Quick checklist ## Quick checklist
- [ ] Merge bottom PR first, `--merge`, no `--delete-branch`. - [ ] Merge bottom PR first, `--merge`, no `--delete-branch`.
- [ ] For each dependent: `gh pr edit <n> --base master` → merge master into the branch (resolve conflicts there) → `gh pr merge <n> --merge`, no `--delete-branch`. - [ ] For each dependent: `gh pr edit <n> --base master` → fetch and merge `origin/master` into the branch (resolve conflicts there, push) → `gh pr merge <n> --merge`, no `--delete-branch`.
- [ ] Run `gh pr list --json number,baseRefName` to confirm no open dependents remain. - [ ] Run `gh pr list --state open --limit 1000 --json number,baseRefName` to confirm no open dependents remain.
- [ ] Delete all branches (local + remote) only as a final pass. - [ ] Delete all branches (local + remote) only as a final pass.

View File

@@ -15,7 +15,7 @@ A wave of review comments lands across several PRs in a dependent stack (`A ←
2. Map each accepted finding to its originating PR, fix it there, then merge down the chain in order. 2. Map each accepted finding to its originating PR, fix it there, then merge down the chain in order.
3. Delegated fixes are trust-but-verify: a sub-agent's report describes intent, not necessarily what landed. Re-run the gates yourself on the actual tree, and for a regression guard, prove it FAILS on the unfixed code (introduce the regression, watch red, revert) — a guard that passes both ways guards nothing. A sub-agent that reframes a problem as already-handled is a signal to dig in personally. 3. Delegated fixes are trust-but-verify: a sub-agent's report describes intent, not necessarily what landed. Re-run the gates yourself on the actual tree, and for a regression guard, prove it FAILS on the unfixed code (introduce the regression, watch red, revert) — a guard that passes both ways guards nothing. A sub-agent that reframes a problem as already-handled is a signal to dig in personally.
4. Reply in the review thread (`gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies`), not as a top-level comment, stating the fix and the commit that carries it. 4. Reply in the review thread (`gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies`), not as a top-level comment, stating the fix and the commit that carries it.
5. Before merging the stack, check dependents: deleting a PR's base branch auto-closes the dependent PR — `gh pr list --json number,baseRefName` first, and merge without `--delete-branch` where a child still bases on the branch. The full landing procedure is the [dsh-merging-stacked-prs](../../.agents/skills/dsh-merging-stacked-prs/SKILL.md) skill. 5. Before merging the stack, check dependents: deleting a PR's base branch auto-closes the dependent PR — `gh pr list --state open --limit 1000 --json number,baseRefName` first (the explicit `--limit` defeats pagination), and merge without `--delete-branch` where a child still bases on the branch. The full landing procedure is the [dsh-merging-stacked-prs](../../.agents/skills/dsh-merging-stacked-prs/SKILL.md) skill.
## Verify ## Verify