stacked-pr
Skill1 starsChanged 11 days agoMITView on GitHub
Build and land a stack of dependent pull requests. Use when the user wants a new PR that sits on top of the PR they are already working on, when a lower branch in a stack changed and everything above it needs rebasing, or when the stack is approved and has to be merged down into dev one layer at a time. Reads the stack from the PR target branches, rebases with --onto, retargets each PR, and completes them in order. Triggers on "stacked pr", "/stacked-pr", "stack a pr on this one", "new pr on top of this pr", "restack", "update the stack", "merge the stack", "land the stack", "my pr depends on another pr".
- Deletes or force-pushes
- Commits and pushes
3 other projects use a version of this.
Adopted by
Most recently taken up by
- LuisUrrutia/skillstheir own version, first seen Oct 18, 2026
- nir-mo/gh-stack-pr-skilltheir own version, first seen Oct 15, 2026
- OutThisLife/brooklyn-skillstheir own version, first seen Jul 23, 2026
Other versions3 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 3
- OutThisLife/brooklyn-skills★ 207same name
- LuisUrrutia/skills★ 2same name
- nir-mo/gh-stack-pr-skill★ 1same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
The file
Show its rules and text
We split this skill into the rules it gives an agent
19 rules. 0 are common, 14 are distinctive, and 5 are very specific to this project.
0
Common
Most of the 3 edited versions we read keep these.
14
Distinctive
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Very specific: line 30
The one rule: the stack moves bottom-up: Never merge a layer before the one below it.
- Distinctive: line 45
Never guess the stack. Azure DevOps has no stack view, so the PR target branches *are* the stack.
- Distinctive: line 78
Use when the user is on a branch with an open PR and wants the next piece of work to build on it.
- Distinctive: line 89
If the second command prints commits, the parent branch is behind the remote.
- Distinctive: line 101
Follow the repo's branch naming.
- Distinctive: line 109
4. Push the branch: Ask first — pushing is the user's call.
- Distinctive: line 130
Always put the dependency in the description.
- Distinctive: line 140
Use when the user pushed a fix to a lower layer (usually from review feedback) and the layers above still carry the old commits.
- Distinctive: line 164
2. Push every branch that moved: Ask before pushing.
- Very specific: line 170
Never --force. --force-with-lease refuses when the remote has commits you have not seen, which is what stops you from erasing a teammate's …
- Distinctive: line 173
3. Tell the user what votes they just lost: If the repo resets votes on new pushes, every layer you pushed needs re-approval even though …
- Very specific: line 204
Add --squash true only if the user asks for it.
- Very specific: line 226
Check the output says refs/heads/dev.
- Very specific: line 242
Read it as: take the commits after $OLD_PARENT up to <top-branch>, and replay them on origin/dev.
- Distinctive: line 268
Only once the layer above is retargeted and pushed:
- Distinctive: line 301
If the same conflict comes back on every layer, the split is wrong — two layers are editing the same lines.
- Distinctive: line 316
If someone else has pulled a layer, stop and tell the user before rewriting.
- Distinctive: line 325
Check with git remote -v. The git half is identical.
- Distinctive: line 351
Never say a layer landed without having read its PR status back from the API.
“Common” is measured: kept by at least 6 in 10 of the 3 edited versions of this file we could read. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Stacked PRs
A stack is a chain of branches where each one is cut from the one below it, not
from dev. Each PR targets the branch below it. Only the bottom PR targets
dev.
dev
└── feat/a PR 1 → dev
└── feat/b PR 2 → feat/a
└── feat/c PR 3 → feat/bEach PR holds only its own diff, so each one is small enough to review.
The one rule: the stack moves bottom-up. Never merge a layer before the one
below it. Never cut a stacked branch from dev.
This skill has three modes. Read the user's ask and pick one:
| The user wants | Mode |
| A new PR on top of the current one | A — Stack |
| A lower branch changed, fix the ones above | B — Restack |
| The stack is approved, get it into dev | C — Land |
Phase 0 — read the stack (every mode starts here)
Never guess the stack. Azure DevOps has no stack view, so the PR target branches are the stack. Read them.
git fetch origin --prune
git status --short
git branch --show-current
az repos pr list --status active \
--query "[].{id:pullRequestId,src:sourceRefName,tgt:targetRefName,draft:isDraft,merge:mergeStatus}" \
-o tableStrip refs/heads/ from both columns. Start at the current branch and follow
tgt down until you reach dev. That chain is the stack. Walk src upward the
same way to find the layers above.
Show the user the stack as a tree with the PR id on each layer, plus dev at
the bottom, before doing anything.
Stop and report if:
- The working tree is dirty. Name the files. The user decides.
- Two PRs have the same source branch. The stack is ambiguous.
- A PR targets a branch that no longer exists on the remote. That layer is orphaned — a lower branch was deleted too early. Say which, and offer mode C step 3 to repair it.
- The current branch has no PR at all. Then there is no stack yet; mode A still works and the new PR targets the current branch.
Mode A — stack a new PR on the current one
Use when the user is on a branch with an open PR and wants the next piece of work to build on it.
1. Check the branch is pushed. A stacked PR cannot target a branch the remote does not have.
git ls-remote --heads origin "$(git branch --show-current)"
git log --oneline "origin/$(git branch --show-current)..HEAD"If the second command prints commits, the parent branch is behind the remote. Say so and ask before pushing it.
2. Cut the new branch from the current one, not from dev.
git checkout --no-track -b <new-branch>--no-track is not optional. Without it a bare git push can go somewhere the
user did not intend.
Follow the repo's branch naming. Read it, do not invent it:
git branch -a --sort=-committerdate | head -203. The user does the work and commits. This skill does not write code.
4. Push the branch. Ask first — pushing is the user's call.
git push -u origin HEAD:refs/heads/<new-branch>5. Open the PR against the parent branch, not dev.
az repos pr create \
--source-branch <new-branch> \
--target-branch <parent-branch> \
--title "<title>" \
--description "Part N of the <feature> stack." "" "Depends on !<parent-pr-id>. Review and merge that one first." \
--repository <repo> \
--squash false--target-branch <parent-branch> is the whole point. Target dev and the PR
shows the parent's diff too, and the reviewer sees work they already approved.
Always put the dependency in the description. Azure DevOps shows no stack, so the description is the only place a reviewer learns the order.
Do not pass --delete-source-branch. Deleting a branch that a layer above
still targets orphans that PR. Branches get deleted in mode C, last.
Mode B — restack after a lower branch changed
Use when the user pushed a fix to a lower layer (usually from review feedback) and the layers above still carry the old commits.
Git 2.38+ does the whole stack in one rebase. Check first:
git --version1. From the top branch of the stack:
git checkout <top-branch>
git rebase --update-refs <bottom-branch>--update-refs replays every commit from the bottom up and moves each
intermediate branch pointer to its rewritten commit. Without it only the top
branch moves and the middle layers are left pointing at commits that no longer
exist.
A branch checked out in another git worktree will not move. Check
git worktree list first and switch it away.
2. Push every branch that moved. Ask before pushing.
git push --force-with-lease origin <branch-1> <branch-2> <branch-3>Never --force. --force-with-lease refuses when the remote has commits you
have not seen, which is what stops you from erasing a teammate's push.
3. Tell the user what votes they just lost. If the repo resets votes on new pushes, every layer you pushed needs re-approval even though its code did not change. That is a real cost of a restack; name it rather than letting them find out.
Mode C — land the stack into dev
One layer at a time, bottom first. The order inside each layer matters more than the commands.
Before anything, save the bottom branch tip. You need it after the merge and you cannot get it back once the branch is gone.
OLD_PARENT=$(git rev-parse origin/<bottom-branch>)
echo "$OLD_PARENT"Then, for each layer from the bottom:
Step 1 — complete the bottom PR
Ask the user first. Every time. Completing a PR is a merge into dev; it is
never this skill's decision. Show the PR id, title, and mergeStatus, then wait.
az repos pr update --id <bottom-pr-id> --status completedAdd --squash true only if the user asks for it. This repo merges with a merge
commit by default, which keeps the layer's own commits in dev.
Never pass --delete-source-branch here. The layer above still targets this
branch.
Step 2 — retarget the next PR to dev
az repos pr update has no --target-branch flag. The REST API does support
it, so go through az devops invoke:
echo '{"targetRefName": "refs/heads/dev"}' > /tmp/retarget.json
az devops invoke \
--area git --resource pullrequests \
--route-parameters project=<project> repositoryId=<repo> pullRequestId=<next-pr-id> \
--http-method PATCH --api-version 7.1 \
--in-file /tmp/retarget.json --encoding utf-8 \
--query "{id:pullRequestId,tgt:targetRefName}" -o jsonCheck the output says refs/heads/dev. If the call is rejected, PR retargeting
is off for the organisation; fall back to the web UI, More actions → Change
target branch, and say so rather than carrying on.
Step 3 — restack the rest onto dev
This is the step people get wrong. A plain git rebase origin/dev replays the
bottom layer's commits a second time, because the merge made new commit ids for
them. Use --onto so only the layer's own commits move:
git fetch origin
git checkout <top-branch>
git rebase --update-refs --onto origin/dev "$OLD_PARENT" <top-branch>Read it as: take the commits after $OLD_PARENT up to <top-branch>, and
replay them on origin/dev. --update-refs carries every branch in between.
This is correct whether the PR was merged with a merge commit, a squash, or a rebase, so use it in all cases.
Push every branch that moved:
git push --force-with-lease origin <branch-2> <branch-3>Step 4 — check the diff is only this layer
Prove it before telling the user it worked:
git diff --stat origin/dev...<next-branch>
az repos pr show --id <next-pr-id> --query "{tgt:targetRefName,merge:mergeStatus}" -o jsonThe diff must show only the files that layer touches. If the lower layer's files
are in there, the --onto base was wrong. Stop and re-read the stack.
Step 5 — now delete the merged branch
Only once the layer above is retargeted and pushed:
git push origin --delete <bottom-branch>
git branch -D <bottom-branch>Step 6 — repeat
The next layer is now the bottom. Set OLD_PARENT to its old tip and go back to
step 1. Keep going until the last PR targets dev and merges.
Conflicts
A conflict can stop any rebase. It is normal in a stack: the layer below moved.
# resolve the files, then
git add .
git rebase --continueTo back out completely:
git rebase --abort--abort puts every branch in the stack back where it was, including the ones
--update-refs already moved. It is always safe to use.
If the same conflict comes back on every layer, the split is wrong — two layers are editing the same lines. Say so; the fix is to reorder or merge the layers, not to keep resolving.
Safety rules
These hold in every mode.
- Ask before pushing, merging, or completing a PR. Branching, rebasing and reading are fine without asking.
--force-with-lease, never--force.- Delete a branch only after the layer above it has been retargeted.
- One person owns a stack. A rebase rewrites history on every branch in it. If someone else has pulled a layer, stop and tell the user before rewriting.
- Keep the stack short. Three or four layers. Each extra layer is another full restack after every merge.
- Never rebase
dev.
If the remote is GitHub, not Azure DevOps
Check with git remote -v. The git half is identical. Only the PR commands change:
gh pr create --base <parent-branch> --head <new-branch> --title "..." --body "Depends on #<parent-pr>"
gh pr list --state open --json number,headRefName,baseRefName
gh pr edit <next-pr> --base dev
gh pr merge <bottom-pr> --mergeGitHub retargets a child PR by itself when the base branch is deleted, so step 2
is often done for you. Verify it with gh pr view <next-pr> --json baseRefName
instead of assuming.
Report at the end
Short, in this order:
- The stack as a tree, with PR ids, as it stands now
- What changed: branches created, rebased, pushed, PRs created, retargeted or completed
- The verification you actually ran — the
git diff --statoutput and the PR target branch, quoted - What is left to do, and anything you skipped or could not do
Never say a layer landed without having read its PR status back from the API.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

