Manage stacked pull requests on GitHub.
- Visualize your stack with
gh-stack log - Annotate PR descriptions with stack metadata tables
- Rebase entire stacks after local changes
- Land a stack by squash-merging the top PR and closing the rest
- Smaller reviews — Break large changes into reviewable chunks
- Faster iteration — Start work on part 2 while part 1 is in review
- Cleaner history — Each PR tells a focused story
GitHub doesn't natively support stacked PRs — gh-stack fills that gap.
brew tap luqven/gh-stack
brew install gh-stackBuild from source
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
export PATH="$HOME/.cargo/bin:$PATH"
cargo install --force --path .export GHSTACK_OAUTH_TOKEN='<personal access token>' # repo scope required
# Optional: override auto-detected repository
export GHSTACK_TARGET_REPOSITORY='owner/repo'You can also set these in a .gh-stack.env file.
Visualize your stack. Learn more
gh-stack log 'STACK-ID'
gh-stack log 'STACK-ID' --short # compact list view
gh-stack log 'STACK-ID' --status # show CI/approval/merge statusSee also: gh-stack status for detailed stack health indicators.
Example output
◉ feat/part-3 (current)
│ 2 hours ago
│
│ a1b2c3d - Add validation logic
│ f4e5d6c - Update tests
│
◯ feat/part-2
│ 3 hours ago
│
│ 1a2b3c4 - Implement core feature
│
◯ feat/part-1
│ 5 hours ago
│
│ 9z8y7x6 - Initial scaffolding
│
◯ main
Add a markdown table to each PR description. Learn more
gh-stack annotate 'STACK-ID'
gh-stack annotate 'STACK-ID' --badges # shields.io badges (public repos)
gh-stack annotate 'STACK-ID' --ci # skip confirmationExample output
This adds a table to each PR description:
### Stack: STACK-ID
| PR | Title | Base |
|:--:|:------|:----:|
| #103 | [STACK-ID] Add validation | #102 |
| #102 | [STACK-ID] Implement feature | #101 |
| #101 | [STACK-ID] Initial scaffolding | main |GitHub auto-links PR numbers, showing status on hover.
Squash-merge the topmost approved PR and close the rest. Learn more
gh-stack land 'STACK-ID'
gh-stack land 'STACK-ID' --dry-run # preview changes
gh-stack land 'STACK-ID' --count 2 # only land bottom 2 PRs
gh-stack land 'STACK-ID' --no-approval # skip approval checkRebuild and push a stack after local changes. Learn more
gh-stack autorebase 'STACK-ID' -C /path/to/repo
gh-stack autorebase 'STACK-ID' -C /path/to/repo --ci # skip confirmationGenerate a bash script for manual rebasing. Learn more
gh-stack rebase 'STACK-ID' > rebase.sh- Create branches that build on each other
- Push and create PRs with a shared identifier (e.g.,
[TICKET-123]) - Set each PR's base to the branch below it
- Use
gh-stack annotateto add stack tables - Use
gh-stack autorebaseto sync - Use
gh-stack landwhen ready to merge
- All PRs in a stack share a unique identifier in their title
- All PRs live in a single GitHub repository
- Remote branches have matching local branch names
See docs/troubleshooting.md for common issues and solutions.
Use at your own risk. The autorebase command modifies git history and force-pushes.
See AGENTS.md for coding guidelines.
# Update version in Cargo.toml
git commit -m "chore: release vX.Y.Z"
git tag vX.Y.Z
git push origin master vX.Y.ZOriginally created by @timothyandrew. See his blog post on stacked PRs.