Stacked PRs
Create stacked PRs for a chain of local branches. Follow the steps below precisely.
Arguments
If arguments are passed via args, interpret them as:
- Branch names or glob patterns to include
- A qualifier prefix (e.g.,
nix-refactor) to use in PR titles - A stack letter override (default:
n)
If no arguments are given, infer the branch stack from the current branch's ancestry.
Step 0: Gather context
Before anything else, run these to understand repo state:
git branch --show-current— current branchgit branch --list— all local branchesgit log --oneline --graph --all --decorate -30— recent log across branchesgit branch -r— remote branchesgh repo view --json nameWithOwner -q '.nameWithOwner'— owner/repo
Step 1: Determine the branch stack
Identify the linear chain of branches from the main branch (usually master or main) to the current or specified branch tip. Use git merge-base to confirm parent-child relationships. Exclude branches with no unique commits vs their parent.
Output the stack as an ordered list before proceeding.
Step 2: Determine the qualifier and stack letter
- If the branch names share a common prefix (e.g.,
nix-refactor/1-...,nix-refactor/2-...), extract it as the qualifier. - If no common prefix exists, ask the user for a qualifier or skip it.
- Default stack letter is
n. If the user specifies a letter, use that instead.
Step 3: Push all branches
Push all branches in the stack to origin with -u in a single command.
Step 4: Create PRs
For each branch in order (bottom of stack first):
- Base branch: The previous branch in the stack, or the main branch for the first PR.
- Title format:
[qualifier][x/letter] conventional-commit-style-titlewhere the title is derived from the branch name or commit content. If no qualifier, omit that prefix. - Body format:
# Description
<1-2 sentences or bullet-only description of the FINAL STATE this PR achieves>
<Additional bullets as needed>
# Test
- [ ] <test checklist items>
Description rules:
- A PR body is not a regurgitation of the diff. It is a high-level explainer that helps the reviewer understand what the PR delivers and why, framed around intent and final state.
- Describe the final state, NOT the commit history. Do NOT mention commits that were overwritten or reversed within the PR.
- Top-level bullets carry the high-level outcomes (one bullet per major theme/outcome). Keep them short — a reviewer should be able to skim them and understand the shape of the change.
- Use nested bullets sparingly for low-level details that genuinely help the reviewer (e.g., a non-obvious side effect, a migration adding a column, a behavior change a reviewer might miss). Do not nest details that are self-evident from the top-level bullet or from filenames.
- For commits/areas with many line changes, take extra care: collapse them into a single intent-level bullet rather than enumerating subsystems. If the breadth itself matters (e.g., a rename across many files), say so in one sentence — do not list the files.
- Never paste raw identifiers from the codebase that only mean something to the implementer, including but not limited to: Alembic migration revision hashes, commit SHAs, internal task IDs, randomly-generated names. Reference the artifact by purpose ("a migration adds the column", "a new background task") instead.
- Sub-sections (
## Foo) are allowed when the PR genuinely spans distinct concerns (see PR #23 /[v1][18/n]inmycustomai/valido-backendas the canonical example for a multi-area PR). For a single-theme PR, skip sub-sections. - Use an exploration agent (sonnet model) to validate claims and understand changes before writing the description. Read the actual diff, not just commit messages.
Anti-patterns to avoid (taken from real revisions):
- Long top-level bullets that pack 4+ subsystems and several class names into one sentence — split or hoist to nested bullets.
- Including migration revision strings like
f1a2b3c4d5e6or chain references like "chained offd7e8f9a0b1c2". The reviewer does not need these; the migration file does. - Restating filenames as if they were features ("Adds
services/analysis/mocks.py"). Describe the capability, mention the path only if it aids navigation. - Bullets that read like a changelog of internal symbol moves with no user-visible effect. Either omit, or compress into a single "supporting refactors" line.
Step 5: Resolve merge conflicts
After creating PRs, check each PR's mergeable status via gh pr view N --json mergeable. If any PR is CONFLICTING:
- Checkout the conflicting branch.
- Merge its base branch with
git merge --no-commit --no-ff <base>. - Resolve conflicts (prefer the feature branch's version for intentional changes).
- Commit the merge resolution.
- Push the updated branch.
- Cascade: merge the updated branch into any downstream branches in the stack, commit, and push each.
- Re-check all PRs for mergeable status.
Step 6: Report
Output a summary table:
| # | PR | Title | Status |
|---|---|---|---|
| 1 | owner/repo#N | [qualifier][1/n] title | MERGEABLE |
| ...