gh-stack
Skill4 starsChanged 3 months agoMITView on GitHub
Manage stacked branches and pull requests with the gh-stack GitHub CLI extension. Use when the user wants to create, push, rebase, sync, navigate, or view stacks of dependent PRs. Triggers on tasks involving stacked diffs, dependent pull requests, branch chains, or incremental code review workflows.
43 other projects use a version of this, 11 of them edited.
Adopted by
Most recently taken up by
- githubnext/chopintheir own version, first seen Nov 8, 2026
- ErikaAX08/erikas-skillstheir own version, first seen Nov 8, 2026
- devantler-tech/ksailtheir own version, first seen Nov 7, 2026
- theexperiencecompany/gaiatheir own version, first seen Nov 3, 2026
- cloudposse/atmostheir own version, first seen Nov 1, 2026
- Egoushka/agent-skillstheir own version, first seen Nov 1, 2026
Used with
Projects with it also use gh-create-pr, gh-commit and 10 more.
Other files people use alongside this one.
Files found in the same public projects as a version of this one, more often than they turn up anywhere else. Each project counts once, large collections count for less, and this file's own repository is left out.
ant-designSkillgh-create-pr
使用 GitHub CLI (gh) 推送当前分支并创建或更新 PR。在用户说「提 PR」「新建 PR」「用 gh 建 PR」「submit PR」「create pull request」时使用。
Also in 4 projects that use this
kelvincushmanSkillgh-commit
Create well-formatted commits with conventional commit format.
Also in 3 projects that use this
kelvincushmanSkillprek
Use when setting up or running hooks with prek in any repository. prek is a Rust drop-in alternative to pre-commit for running Git hooks that check, format, lint, and validate code and repository files. Prefer it when speed, workspace mode, built-in hooks, shared toolchains, or native TOML configuration matter.
Also in 3 projects that use this
carapace-shSkillbun
Use when working with the bun CLI — Bun's all-in-one JavaScript runtime and toolkit. Covers the CLI command reference (install, add, remove, run, build, test, x, create, init, pm, upgrade, link, unlink), bunfig.toml configuration, environment variables, the package manager and lockfile, the test runner, the bundler, the Bun runtime API (Bun.serve, Bun.file, Bun.spawn, Bun.write, hashing, transpiler), the Bun shell ($ template literal), module resolution and loaders, and globals. Triggers on: "bun", "bunx", "bun install", "bun add", "bun remove", "bun run", "bun build", "bun test", "bun x", "bun create", "bun init", "bun pm", "bun upgrade", "bun link", "bun unlink", "bunfig.toml", "bun.lock", "Bun.serve", "Bun.file", "Bun.write", "Bun.spawn", "Bun.hash", "Bun.password", "bun:test", "Bun.build", "Bun.Transpiler", "bun shell", "$ template", "import.meta", "JavaScriptCore", "Bun.serve", "HTMLRewriter", "Bun.SQL", "Bun.RedisClient", "Bun.Glob", "Bun.plugin", "bun:ffi".
Also in 3 projects that use this
xfstudioSkilltypescript-expert
TypeScript and JavaScript expert with deep knowledge of type-level programming, performance optimization, monorepo management, migration strategies, and modern tooling. Use PROACTIVELY for any TypeScript/JavaScript issues including complex type gymnastics, build performance, debugging, and architectural decisions. If a specialized expert is a better fit, I will recommend switching and stop.
Also in 3 projects that use this
xfstudioSkilltypescript-advanced-types
Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications. Use when implementing complex type logic, creating reusable type utilities, or ensuring compile-time type safety in TypeScript projects.
Also in 4 projects that use this
Other versions43 projects use a version of this.
Word for word · 0
None found.
Edited · 11
- dotnet/macios★ 2.9k65% same
- dotnet/android★ 2.1k65% same
- NVIDIA-NeMo/Gym★ 1.3k67% same
- bastani-inc/atomic★ 88163% same
- flora131/atomic★ 88163% same
- PLC-lang/rusty★ 37263% same
- kelvincushman/orphus★ 463% same
- adrienlupo/Claude-code-config★ 363% same
- knitli/toolshed★ 163% same
- LinnJS/skills★ 163% same
1 more not listed
Wrote their own version · 32
- vercel/next.js★ 143ksame name
- remotion-dev/remotion★ 72ksame name
- CherryHQ/cherry-studio★ 53ksame name
- Arize-ai/phoenix★ 12ksame name
- trycompai/crm★ 12ksame name
- CherryHQ/cherry-studio-app★ 4.1ksame name
- github/gh-stack★ 1.8ksame name
- cloudposse/atmos★ 1.4ksame name
- learntocloud/learn-to-cloud-app★ 1.1ksame name
- Kotlin/kotlinx-rpc★ 1.1ksame name
22 more not listed
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.
In this repository21 other files it gives its agents.
- templates/AGENTS.mdAGENTS.md
- architecture-doc-builderSkill
- confluenceSkill
- conformanceSkill
- doc-checkSkill
- feature-doc-builderSkill
- gh-issueSkill
- gh-wikiSkill
- handoffSkill
- jiraSkill
- pr-builderSkill
- proposal-builderSkill
- pr-reviewSkill
- psqlSkill
- qa-testingSkill
- spec-builderSkill
- spec-drivenSkill
- sqlcmdSkill
- standard-builderSkill
- worktreeSkill
- zazz-boardSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
36 rules. 0 are common, 14 are distinctive, and 22 are very specific to this project.
0
Common
Most of the 42 edited versions we read keep these.
14
Distinctive
This author's own choices. Worth a look.
22
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 21
Use the locally managed gh-stack workflow only for a traditional Git branch stack in which every stacked branch is available from one …
- Distinctive: line 29
Use this skill when the user wants to:
- Distinctive: line 32
Create, rebase, push, or sync a stack of dependent branches
- Distinctive: line 72
When the repository has GitHub Stacked PRs enabled, a PR in a stack shows a stack map at the top of its PR page.
- Very specific: line 77
Use that reference for methodology and examples.
- Very specific: line 80
Before using gh stack, configure git to prevent interactive prompts:
- Very specific: line 89
All
gh stackcommands must be run non-interactively: Every command invocation must include the flags and positional arguments needed to … - Very specific: line 92
Use flat, dash-separated branch names: Do not use / in a branch name.
- Distinctive: line 96
Avoid branches shared across multiple stacks: If a branch belongs to multiple stacks, commands exit with code 6.
- Very specific: line 100
Use
gh stack linkfor external tool workflows: When branches are managed by an external tool (jj, Sapling, etc.), use gh stack link … - Very specific: line 153
Always pass the complete flat branch name to gh stack add.
- Very specific: line 179
Use Git to place content; gh-stack does not move files or hunks.
- Distinctive: line 192
After every correction, run:
- Very specific: line 205
Create a new branch (gh stack add) when you're starting a different concern that depends on what you've built so far.
- Distinctive: line 216
When to use a single stack: All the branches are part of the same feature, project, or closely related effort.
- Distinctive: line 363
When you need to revisit a branch after the initial creation (e.g., responding to review feedback):
- Very specific: line 395
When a PR is squash-merged on GitHub, the original branch's commits no longer exist in the trunk history.
- Very specific: line 412
If sync hits a conflict during this process, it restores all branches to their pre-rebase state and exits with code 3.
- Very specific: line 464
Use unstack to tear down the stack, make structural changes, then re-init:
- Very specific: line 508
Use flat names such as my-feature-1.
- Distinctive: line 518
Add a new branch on top of the current stack.
- Very specific: line 558
When the current branch has no commits (e.g., right after init), add -Am commits directly on the current branch instead of creating a new …
- Very specific: line 559
Branch names: Always pass the full flat branch name, for example my-feature-2.
- Very specific: line 560
If called from a branch that is not the topmost in the stack, exits with code 5: "can only add branches on top of the stack".
- Distinctive: line 619
After creating PRs, links them together as a Stack on GitHub (requires the repository to have stacks enabled)
- Very specific: line 620
If stacks are not available (exit code 9), the repository does not have stacked PRs enabled.
- Distinctive: line 671
If the PRs are not yet in a stack, a new stack is created.
- Distinctive: line 700
Cascade rebase: all stack branches onto their updated parents (only if trunk moved).
- Distinctive: line 701
Push: all active branches atomically
- Very specific: line 755
Merged PR detection: If a branch's PR was merged on GitHub, the rebase automatically handles this using --onto mode and correctly replays …
- Very specific: line 841
Check out a stack from a pull request number or branch name.
- Very specific: line 855
When a PR number is provided (e.g.
- Distinctive: line 859
When a branch name is provided, the command resolves it against locally tracked stacks only.
- Very specific: line 898
When piping output, use 2>/dev/null to suppress status messages if only data output is needed.
- Distinctive: line 918
Stack disambiguation cannot be bypassed: If the current branch is the trunk of multiple stacks, commands error with code 6.
- Very specific: line 919
Multiple remotes require
--remoteor config: If more than one remote is configured, pass --remote <name> or set remote.pushDefault in git …
“Common” is measured: kept by at least 6 in 10 of the 42 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
gh-stack
gh stack is a GitHub CLI extension for managing stacked branches and pull requests. A stack is an ordered list of branches where each branch builds on the one below it, rooted on a trunk branch (typically the repo's default branch). Each branch maps to one PR whose base is the branch below it, so reviewers see only the diff for that layer.
main (trunk)
└── feature-auth-1 → PR #1 (base: main) - bottom (closest to trunk)
└── feature-auth-2 → PR #2 (base: feature-auth-1)
└── feature-auth-3 → PR #3 (base: feature-auth-2) - top (furthest from trunk)The bottom of the stack is the branch closest to the trunk, and the top is the branch furthest from the trunk. Each branch inherits from the one below it. Navigation commands (up, down, top, bottom) follow this model: up moves away from trunk, down moves toward it.
Scope: one shared stack-lane worktree
Use the locally managed gh-stack workflow only for a traditional Git branch stack in
which every stacked branch is available from one shared stack-lane worktree. Do not
use it for a set of stacked branches separately checked out into individual worktrees;
use separate worktrees and ordinary PRs for that case. This guardrail applies before any
init, checkout, navigation, rebase, push, sync, or submit command is run.
When to use this skill
Use this skill when the user wants to:
- Break a large change into a chain of small, reviewable PRs
- Create, rebase, push, or sync a stack of dependent branches
- Navigate between layers of a branch stack
- View the status of stacked PRs
- Tear down and rebuild a stack to remove, reorder, or rename branches
Prerequisites and version check
The GitHub CLI (gh) v2.0+ must be installed and authenticated. Install the extension with:
gh extension install github/gh-stackOfficial CLI reference: https://github.github.com/gh-stack/reference/cli/
GitHub Stacked PRs is preview functionality. Confirm that the repository has it enabled before using this skill. The extension is evolving, so before issuing a state-changing command, run gh stack <command> --help and use the flags supported by the installed version. The current website and older installed extensions differ on init adoption and draft-PR flags.
This is the Zazz-adapted skill. Do not replace it with the generic upstream gh-stack skill: upstream documentation and command help define CLI behavior, while this skill defines the Zazz lane, naming, agent, file-placement, and review rules. Update and validate this skill deliberately when upstream gh-stack behavior changes.
Bundled workflow reference
For the methodology's required local stack-lane workflow, read
references/single-worktree-lane.md in this skill directory. It explains the preferred
model for agent work:
- one shared worktree = one gh-stack execution lane for a complex initiative
- one stack inside that worktree = multiple dependent deliverables, each with one branch and one reviewable PR
- one branch = one deliverable review unit, represented by commits, not by a remembered file list
Full local gh-stack operations require all branches in the stack to be available to the
same worktree. Do not put stack branches in separately checked-out worktrees: Git blocks
the navigation commands from checking out a branch already checked out elsewhere. Use
separate sibling worktrees and ordinary PRs for independent concurrent work. gh stack
link is an advanced remote-only option when another tool owns local branch management;
it is not the methodology's default separate-worktree workflow.
When the repository has GitHub Stacked PRs enabled, a PR in a stack shows a stack map at the top of its PR page. It exposes the PRs in the stack, their status, and direct navigation between layers. This preview UI is reviewer context only; the specification, acceptance evidence, and normal PR review remain required.
Use that reference for methodology and examples; use this SKILL.md for command rules
and non-interactive gh stack usage.
Before using gh stack, configure git to prevent interactive prompts:
git config rerere.enabled true # remember conflict resolutions (skips prompt on init)
git config remote.pushDefault origin # if multiple remotes exist (skips remote picker)Agent rules
All gh stack commands must be run non-interactively. Every command invocation must include the flags and positional arguments needed to avoid prompts, TUIs, and interactive menus. If a command would prompt for input, it will hang indefinitely.
- Always supply branch names as positional arguments to
init,add, andcheckout. Running these commands without arguments triggers interactive prompts. - Use flat, dash-separated branch names. Do not use
/in a branch name. Older gh-stack versions offergh stack init -p; do not use that mode in this methodology because it creates slash-separated names. - Always use
--autowithgh stack submitto auto-generate PR titles. Without--auto,submitprompts for a title for each new PR. - Always use
--jsonwithgh stack view. Without--json, the command launches an interactive TUI that cannot be operated by agents. There is no other appropriate flag — always pass--json. - Use
--remote <name>when multiple remotes are configured, or pre-configuregit config remote.pushDefault origin. Without this,push,submit,sync,link, andcheckouttrigger an interactive remote picker. - Avoid branches shared across multiple stacks. If a branch belongs to multiple stacks, commands exit with code 6. Check out a non-shared branch first.
- Plan your stack layers by dependency order before writing code. Foundational changes (models, APIs, shared utilities) go in lower branches; dependent changes (UI, consumers) go in higher branches. Think through the dependency chain before running
gh stack init. - Use standard
git addandgit commitfor staging and committing. This gives you full control over which changes go into each branch. The-Amshortcut is available but should not be the default approach—stacked PRs are most effective when each branch contains a deliberate, logical set of changes. - Navigate down the stack when you need to change a lower layer. If you're working on a frontend branch and realize you need API changes, don't hack around it at the current layer. Navigate to the appropriate branch (
gh stack down,gh stack checkout, orgh stack bottom), make and commit the changes there, rungh stack rebase --upstack, then navigate back up to continue. - Use
gh stack linkfor external tool workflows. When branches are managed by an external tool (jj, Sapling, etc.), usegh stack link branch-a branch-b.linkdoes not rely on local tracking state and is intended for API-driven PR and stack management. Always provide at least 2 branch names or PR numbers.
Never do any of the following — each triggers an interactive prompt or TUI that will hang:
- ❌
gh stack vieworgh stack view --short— always usegh stack view --json - ❌
gh stack submitwithout--auto— always usegh stack submit --auto - ❌
gh stack initwithout branch arguments — always provide branch names - ❌
gh stack addwithout a branch name — always provide a branch name - ❌
gh stack checkoutwithout an argument — always provide a PR number or branch name - ❌
gh stack checkout <pr-number>when a different local stack already exists on those branches — this triggers an unbypassable conflict resolution prompt; usegh stack unstackfirst to remove the local stack, then retry the checkout
Thinking about stack structure
Each branch in a stack should represent a discrete, logical unit of work that can be reviewed independently. The changes within a branch should be cohesive—they belong together and make sense as a single PR.
Dependency chain
Stacked branches form a dependency chain: each branch builds on the one below it. This means foundational changes must go in lower (earlier) branches, and code that depends on them goes in higher (later) branches.
Plan your layers before writing code. For example, a full-stack feature might be structured like this (use branch names relevant to your actual task, not these generic ones):
main (trunk)
└── feature-auth-1 ← shared types, database schema
└── feature-auth-2 ← API routes that use the models
└── feature-auth-3 ← UI components that call the APIs
└── feature-auth-4 ← end-to-end testsThis is illustrative — choose branch names and layer boundaries that reflect the specific work you're doing. The key principle is: if code in one layer depends on code in another, the dependency must be in the same branch or a lower one.
Branch naming
For a Zazz stack lane, the recommended (not required) convention is to name the worktree after the initiative and number its stack branches in dependency order:
worktree: my-feature
branches: my-feature-1 → my-feature-2 → my-feature-3For example, my-feature-1 is the bottom branch based on the integration branch, and
my-feature-2 is created on top of it. This makes stack membership and order visible
without relying on the gh-stack UI:
git worktree add ../my-feature -b my-feature-1 <integration-branch>
cd ../my-feature
gh stack init --base <integration-branch> my-feature-1
# Older extensions: gh stack init --base <integration-branch> --adopt my-feature-1
gh stack add my-feature-2
gh stack add my-feature-3Always pass the complete flat branch name to gh stack add. Do not use the -p prefix
mode offered by older gh-stack versions because it creates slash-separated branch names.
Staging changes deliberately
The main reason to use git add and git commit directly is to control which changes go into which branch. When you have multiple files in your working tree, you can stage a subset for the current branch, commit them, then create a new branch and stage the rest there:
# You're on feature-auth-1 with several new files in your working tree.
# Stage only the model files for this branch:
git add internal/models/user.go internal/models/session.go
git commit -m "Add user and session models"
git add db/migrations/001_create_users.sql
git commit -m "Add user table migration"
# Now create a new branch for the API layer and stage the API files there:
gh stack add feature-auth-2
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"This keeps each branch focused on one concern. Multiple commits per branch are fine — the key is that all commits in a branch relate to the same logical concern, and changes that belong to a different concern go in a different branch.
Correct misplaced changes
Use Git to place content; gh-stack does not move files or hunks. Prefer one branch owner
per file when practical. An upper branch may change the same file only for a distinct
reviewable reason.
- Uncommitted file: stash the path, check out the correct lower branch, restore it, and
commit it there. Use path-specific staging; reserve
git add -pfor a human interactive session when hunks must be separated. - Whole commit:
git cherry-pick <wrong-commit>onto the correct lower branch. A later rebase may drop the duplicate patch or require conflict resolution. - Mixed committed change:
gh stack modifycannot split it. Reconstruct an unpublished change with normal Git staging. For published history, agree a correction plan with the Deliverable Owner or Lead Contributor Agent before rewriting it.
After every correction, run:
gh stack rebase --upstack
gh stack checkout <corrected-upper-branch>
git diff --name-only <immediate-parent-branch>...HEADConfirm that the immediate-parent diff contains only the upper deliverable, then rerun the relevant tests before push or submit.
When to create a new branch
Create a new branch (gh stack add) when you're starting a different concern that depends on what you've built so far. Signs it's time for a new branch:
- You're switching from backend to frontend work
- You're moving from core logic to tests or documentation
- The next set of changes has a different reviewer audience
- The current branch's PR is already large enough to review
One stack, one story
Think of a stack from the reviewer's perspective: the stack of PRs should tell a cohesive story about a feature or project. A reviewer should be able to read the PRs in sequence and understand the progression of changes, with each PR being a small, logical piece of the whole.
When to use a single stack: All the branches are part of the same feature, project, or closely related effort. Even if the work spans multiple concerns (models, API, frontend), they're all building toward the same goal.
When to create a separate stack: The work is unrelated to your current stack — a different feature, a bug fix in an unrelated area, or an independent refactor. Don't mix unrelated work into a single stack just because you happen to be working on both. Start a new stack with gh stack init or switch to an existing stack with gh stack checkout for each distinct effort.
Small, incidental fixes (e.g., fixing a typo you noticed) can go in the current stack if they're trivial. But if a change grows into its own project, it deserves its own stack.
Quick reference
| Task | Command |
| Create a stack | gh stack init feature-auth-1 |
| Initialize an existing branch sequence | gh stack init branch-a branch-b (older extensions: add --adopt) |
| Set custom trunk | gh stack init --base develop branch-a |
| Add a branch to stack | gh stack add feature-auth-2 |
| Add branch + stage all + commit | gh stack add -Am "message" feature-auth-2 |
| Push branches to remote | gh stack push |
| Push to specific remote | gh stack push --remote origin |
| Push branches + create PRs | gh stack submit --auto |
| Create draft PRs | gh stack submit --auto (older extensions: add --draft) |
| Sync (fetch, rebase, push) | gh stack sync |
| Sync with specific remote | gh stack sync --remote origin |
| Rebase entire stack | gh stack rebase |
| Rebase upstack only | gh stack rebase --upstack |
| Continue after conflict | gh stack rebase --continue |
| Abort rebase | gh stack rebase --abort |
| View stack details (JSON) | gh stack view --json |
| Switch branches up/down in stack | gh stack up [n] / gh stack down [n] |
| Switch to top/bottom branch | gh stack top / gh stack bottom |
| Check out by PR | gh stack checkout 42 |
| Check out by branch (local only) | gh stack checkout feature-auth |
| Tear down a stack to restructure it | gh stack unstack |
Workflows
End-to-end: create a stack from scratch
# 1. Initialize a stack with the first flat branch
gh stack init feature-auth-1
# → creates feature-auth-1 and checks it out
# 2. Write code for the first layer (auth)
cat > auth.go << 'EOF'
package auth
func Middleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// verify token
next.ServeHTTP(w, r)
})
}
EOF
# 3. Stage and commit using standard git commands
git add auth.go
git commit -m "Add auth middleware"
# You can make multiple commits on the same branch
cat > auth_test.go << 'EOF'
package auth
func TestMiddleware(t *testing.T) {
// test auth middleware
}
EOF
git add auth_test.go
git commit -m "Add auth middleware tests"
# 4. When you're ready for a new concern, add the next branch
gh stack add feature-auth-2
# → creates feature-auth-2
# 5. Write code for the API layer
cat > api.go << 'EOF'
package api
func RegisterRoutes(mux *http.ServeMux) {
mux.HandleFunc("/users", handleUsers)
}
EOF
git add api.go
git commit -m "Add API routes"
# 6. Add a third layer for frontend
gh stack add feature-auth-3
# → creates feature-auth-3
cat > frontend.go << 'EOF'
package frontend
func RenderDashboard(w http.ResponseWriter) {
// calls the API endpoints from the layer below
}
EOF
git add frontend.go
git commit -m "Add frontend dashboard"
# ── Stack complete: feature-auth-1 → feature-auth-2 → feature-auth-3 ──
# 7. Push everything and create draft PRs (current website default)
gh stack submit --auto
# Older extensions: gh stack submit --auto --draft
# 8. Verify the stack
gh stack view --jsonShortcut: If you prefer a faster flow,
gh stack add -Am "message" branch-namecombines staging, committing, and branch creation into one command. This is useful for single-commit layers but bypasses deliberate staging.
Making mid-stack changes
This is a critical workflow for agents. When you're working on a higher layer and realize you need to change something in a lower layer (e.g., you're building frontend components but need to add an API endpoint), navigate down to the correct branch, make the change there, and rebase.
# You're on feature-auth-3 but need to add an API endpoint
# 1. Navigate to the API branch
gh stack down
# or: gh stack checkout feature-auth-2
# 2. Make the change where it belongs
cat > users_api.go << 'EOF'
package api
func handleGetUser(w http.ResponseWriter, r *http.Request) {
// new endpoint the frontend needs
}
EOF
git add users_api.go
git commit -m "Add get-user endpoint"
# 3. Rebase everything above to pick up the change
gh stack rebase --upstack
# 4. Navigate back to where you were working
gh stack top
# or: gh stack checkout feature-auth-3
# 5. Continue working — the API changes are now availableWhy this matters: If you make API changes on the frontend branch, those changes will end up in the wrong PR. The API PR won't include them, and the frontend PR will have unrelated API diffs mixed in. Always put changes in the branch where they logically belong.
Modify a mid-stack branch and sync
When you need to revisit a branch after the initial creation (e.g., responding to review feedback):
# 1. Navigate to the branch that needs changes
gh stack bottom
# or: gh stack checkout feature-auth-1
# or: gh stack checkout 42 (by PR number)
# 2. Make changes and commit
cat > auth.go << 'EOF'
package auth
// updated implementation
EOF
git add auth.go
git commit -m "Fix auth token validation"
# 3. Rebase everything above this branch
gh stack rebase --upstack
# 4. Push the updated stack
gh stack pushRoutine sync after merges
# Single command: fetch, rebase, push, sync PR state
gh stack syncSquash-merge recovery
When a PR is squash-merged on GitHub, the original branch's commits no longer exist in the trunk history. gh stack detects this automatically and uses git rebase --onto to correctly replay remaining commits.
# After PR #1 (feature-auth-1) is squash-merged on GitHub:
gh stack sync
# → fetches latest, detects the merge, fast-forwards trunk
# → rebases feature-auth-2 onto updated trunk (skips merged branch)
# → rebases feature-auth-3 onto feature-auth-2
# → pushes updated branches
# → reports: "Merged: #1"
# Verify the result
gh stack view --json
# → feature-auth-1 shows "isMerged": true, "state": "MERGED"
# → feature-auth-2 and feature-auth-3 show updated headsIf sync hits a conflict during this process, it restores all branches to their pre-rebase state and exits with code 3. See Handle rebase conflicts for the resolution workflow.
Handle rebase conflicts (agent workflow)
# 1. Start the rebase
gh stack rebase
# 2. If exit code 3 (conflict):
# - Parse stderr for conflicted file paths
# - Read those files to find <<<<<<< / ======= / >>>>>>> markers
# - Edit files to resolve conflicts
# - Stage resolved files:
git add path/to/resolved-file.go
# 3. Continue the rebase
gh stack rebase --continue
# 4. If another conflict occurs, repeat steps 2-3
# 5. If unable to resolve, abort to restore everything
gh stack rebase --abortParsing --json output
# Get stack state as JSON
output=$(gh stack view --json)
# Check if any branch needs a rebase, and rebase if so
needs_rebase=$(echo "$output" | jq '[.branches[] | select(.needsRebase == true)] | length')
if [ "$needs_rebase" -gt 0 ]; then
echo "Branches need rebase, rebasing stack..."
gh stack rebase
fi
# Get all open PR URLs
echo "$output" | jq -r '.branches[] | select(.pr.state == "OPEN") | .pr.url'
# Find merged branches
echo "$output" | jq -r '.branches[] | select(.isMerged == true) | .name'
# Get the current branch
echo "$output" | jq -r '.currentBranch'
# Check if the stack is fully merged (all branches merged)
echo "$output" | jq '[.branches[] | .isMerged] | all'Restructure a stack (remove a branch, reorder, or rename)
Use unstack to tear down the stack, make structural changes, then re-init:
# 1. Remove the stack (locally and on GitHub)
gh stack unstack
# 2. Make structural changes — e.g. delete a branch, reorder, rename
git branch -m old-branch-1 new-branch-1
# 3. Re-create the stack with the new structure
gh stack init --base main new-branch-1 new-branch-2 new-branch-3
# Older extensions: add --adoptCommands
Initialize a stack — gh stack init
Creates a new stack. Always provide at least one branch name as a positional argument — running without branch arguments triggers interactive prompts that agents cannot use.
gh stack init [flags] <branches...># Create a stack with flat names in dependency order
gh stack init my-feature-1 my-feature-2 my-feature-3
# Use a different trunk branch
gh stack init --base develop my-feature-1 my-feature-2
# Initialize existing branches into a stack (current website behavior)
gh stack init my-feature-1 my-feature-2 my-feature-3
# Older extensions: gh stack init --adopt my-feature-1 my-feature-2 my-feature-3| Flag | Description |
-b, --base <branch> | Trunk branch (defaults to the repo's default branch) |
Behavior:
- Use flat names such as
my-feature-1; do not use-pin this methodology. - Creates any branches that don't already exist (branching from the trunk branch)
- Current website: existing branch names are adopted and missing names are created. Older extensions expose
--adoptfor the existing-branch case; checkgh stack init --help. - Checks out the last branch in the list
- Enables
git rerereso conflict resolutions are remembered across rebases. On first run in a repo, this may trigger a confirmation prompt — pre-configure withgit config rerere.enabled trueto avoid it
Add a branch — gh stack add
Add a new branch on top of the current stack. Must be run while on the topmost branch (or the trunk if the stack has no branches yet). Always provide a branch name — running without one triggers an interactive prompt.
gh stack add [flags] <branch>Recommended workflow — create the branch, then use standard git:
# Create a new flat branch and switch to it
gh stack add my-feature-2
# Write code, stage deliberately, and commit
git add internal/api/routes.go internal/api/handlers.go
git commit -m "Add user API routes"
# Make more commits on the same branch as needed
git add internal/api/middleware.go
git commit -m "Add rate limiting middleware"Shortcut — stage, commit, and branch in one command:
# Create a new branch, stage all changes, and commit
gh stack add -Am "Add API routes" api-routes
# Create a new branch, stage tracked files only, and commit
gh stack add -um "Fix auth bug" auth-fix| Flag | Description |
-m, --message <string> | Create a commit with this message |
-A, --all | Stage all changes including untracked files (requires -m) |
-u, --update | Stage tracked files only (requires -m) |
Behavior notes:
-Aand-uare mutually exclusive.- When the current branch has no commits (e.g., right after
init),add -Amcommits directly on the current branch instead of creating a new one. - Branch names: Always pass the full flat branch name, for example
my-feature-2. Do not use/or prefix mode. - If called from a branch that is not the topmost in the stack, exits with code 5:
"can only add branches on top of the stack". Usegh stack topto switch first. - Uncommitted changes: When using
gh stack add branch-namewithout-Am, any uncommitted changes (staged or unstaged) in your working tree carry over to the new branch. This is standard git behavior — the working tree is not touched. Commit or stash changes on the current branch before runningaddif you want a clean starting point on the new branch.
Push branches to remote — gh stack push
Push all stack branches to the remote.
gh stack push [flags]# Push all branches
gh stack push
# Push to specific remote
gh stack push --remote upstream| Flag | Description |
--remote <name> | Remote to push to (use if multiple remotes exist) |
Behavior:
- Pushes all active (non-merged) branches atomically (
--force-with-lease --atomic) - Does not create or update pull requests — use
gh stack submitfor that
Output (stderr):
Pushed N branchessummary
Submit branches and create PRs — gh stack submit
Push all stack branches and create PRs on GitHub. Always pass --auto — without it, submit prompts for a PR title for each new branch.
# Submit and auto-title new PRs (required for non-interactive use)
gh stack submit --auto
# Current website: non-interactive submit creates drafts by default
gh stack submit --auto
# Older extensions: gh stack submit --auto --draft| Flag | Description |
--auto | Auto-generate PR titles without prompting (required for non-interactive use) |
--open | Mark new PRs ready for review, when supported by the installed version |
--remote <name> | Remote to push to (use if multiple remotes exist) |
Behavior:
- Pushes all active (non-merged) branches atomically (
--force-with-lease --atomic) - Creates a new PR for each branch that doesn't have one (base set to the first non-merged ancestor branch)
- After creating PRs, links them together as a Stack on GitHub (requires the repository to have stacks enabled)
- If stacks are not available (exit code 9), the repository does not have stacked PRs enabled. In interactive mode,
submitoffers to create regular (unstacked) PRs instead. In non-interactive mode, it exits with code 9. - Syncs PR metadata for branches that already have PRs
PR title auto-generation (--auto):
- Single commit on branch → uses the commit subject as the PR title, commit body as PR body
- Multiple commits on branch → humanizes the branch name (hyphens/underscores → spaces) as the title
Output (stderr):
Created PR #N for <branch>for each newly created PRPR #N for <branch> is up to datefor existing PRsPushed and synced N branchessummary
Link branches as a stack (no local tracking) — gh stack link
Link PRs into a stack on GitHub without creating any local tracking state. This is the recommended approach if you are managing stacked branches with other tools (jj, Sapling, git-town) and want to simply create GitHub Stacked PRs via an API.
gh stack link [flags] <branch-or-pr> <branch-or-pr> [...]# Link branches into a stack (pushes, creates PRs, creates stack)
gh stack link branch-a branch-b branch-c
# Use a different base branch
gh stack link --base develop branch-a branch-b branch-c
# Link existing PRs by number
gh stack link 10 20 30
# Add branches to an existing stack of PRs
gh stack link 42 43 feature-auth feature-ui| Flag | Description |
--base <branch> | Base branch for the bottom of the stack (default: main) |
--draft | Create new PRs as drafts when supported by the installed version |
--remote <name> | Remote to push to (use if multiple remotes exist) |
Behavior:
- Arguments are provided in stack order (bottom to top)
- Each argument can be a branch name or a PR number. Numeric arguments are tried as PR numbers first; if no PR with that number exists, the argument is treated as a branch name
- Branch arguments are pushed to the remote automatically (non-force, atomic)
- For branches without open PRs, new PRs are created with auto-generated titles and the correct base branch chaining (first branch uses
--base, subsequent branches use the previous branch) - Existing PRs whose base branch doesn't match the expected chain are corrected automatically
- If the PRs are not yet in a stack, a new stack is created. If some PRs are already in a stack, the stack is updated (additive only — existing PRs are never removed)
- Does not create or modify any local state
Output (stderr):
Pushing N branches to <remote>...Found PR #N for branch <name>for branches with existing PRsCreated PR #N for <branch> (base: <base>)for newly created PRsUpdated base branch for PR #N to <base>when base branches are correctedCreated stack with N PRsorUpdated stack to N PRs
Sync the stack — gh stack sync
Fetch, rebase, push, and sync PR state in a single command. This is the recommended command for routine synchronization.
gh stack sync [flags]| Flag | Description |
--remote <name> | Remote to fetch from and push to (use if multiple remotes exist) |
What it does (in order):
- Fetch latest changes from the remote
- Fast-forward trunk to match remote (skips if already up to date, warns if diverged)
- Cascade rebase all stack branches onto their updated parents (only if trunk moved). Handles merged PRs automatically. If a conflict is detected, all branches are restored to their pre-rebase state and the command exits with code 3 — see Handle rebase conflicts for the resolution workflow
- Push all active branches atomically
- Sync PR state from GitHub and report the status of each PR
Output (stderr):
✓ Fetched latest changes from origin✓ Trunk main fast-forwarded to <sha>or✓ Trunk main is already up to date✓ Rebased <branch> onto <base>per branch (if base moved)✓ Pushed N branches✓ PR #N (<branch>) — Openper branchMerged: #N, #Mfor merged branches✓ Stack synced
Rebase the stack — gh stack rebase
Pull from remote and cascade-rebase stack branches. Use this when sync reports a conflict or when you need finer control (e.g., rebase only part of the stack).
gh stack rebase [flags] [branch]# Rebase the entire stack
gh stack rebase
# Rebase only branches from trunk to current branch
gh stack rebase --downstack
# Rebase only branches from current branch to top
gh stack rebase --upstack
# After resolving a conflict: stage files with `git add`, then:
gh stack rebase --continue
# Abort and restore all branches to pre-rebase state
gh stack rebase --abort| Flag | Description |
--downstack | Only rebase branches from trunk to the current branch |
--upstack | Only rebase branches from the current branch to the top |
--continue | Continue after resolving conflicts |
--abort | Abort and restore all branches |
--remote <name> | Remote to fetch from (use if multiple remotes exist) |
| Argument | Description |
[branch] | Target branch (defaults to the current branch) |
Conflict handling: See Handle rebase conflicts in the Workflows section for the full resolution workflow.
Merged PR detection: If a branch's PR was merged on GitHub, the rebase automatically handles this using --onto mode and correctly replays commits on top of the merge target.
Rerere (conflict memory): git rerere is enabled by init so previously resolved conflicts are auto-resolved in future rebases.
View the stack — gh stack view
Display the current stack's branches, PR status, and recent commits. Always pass --json — without it, this command launches an interactive TUI that agents cannot operate.
# Always use --json
gh stack view --json| Flag | Description |
--json | Output stack data as JSON to stdout (required for non-interactive use) |
--json output format:
{
"trunk": "main",
"currentBranch": "my-feature-2",
"branches": [
{
"name": "my-feature-1",
"head": "abc1234...",
"base": "def5678...",
"isCurrent": false,
"isMerged": true,
"needsRebase": false,
"pr": {
"number": 42,
"url": "https://github.com/owner/repo/pull/42",
"state": "MERGED"
}
},
{
"name": "my-feature-2",
"head": "789abcd...",
"base": "abc1234...",
"isCurrent": true,
"isMerged": false,
"needsRebase": false,
"pr": {
"number": 43,
"url": "https://github.com/owner/repo/pull/43",
"state": "OPEN"
}
}
]
}Fields per branch:
name— branch namehead— current HEAD SHAbase— parent branch's HEAD SHA at last syncisCurrent— whether this is the checked-out branchisMerged— whether the PR has been mergedneedsRebase— whether the base branch is not an ancestor (non-linear history)pr— PR metadata (omitted if no PR exists).stateis"OPEN"or"MERGED".
Navigate the stack
Move between branches without remembering branch names. These commands are fully non-interactive.
gh stack up # Move up one branch (further from trunk)
gh stack up 3 # Move up three branches
gh stack down # Move down one branch (closer to trunk)
gh stack down 2 # Move down two branches
gh stack top # Jump to the top of the stack (furthest from trunk)
gh stack bottom # Jump to the bottom (first non-merged branch above trunk)Navigation clamps to stack bounds. Merged branches are skipped when navigating from active branches.
Check out a stack — gh stack checkout
Check out a stack from a pull request number or branch name. Always provide an argument — running gh stack checkout without arguments triggers an interactive selection menu.
gh stack checkout <pr-number | branch># By PR number (pulls from GitHub)
gh stack checkout 42
# By branch name (local only)
gh stack checkout feature-authWhen a PR number is provided (e.g. 123), the command fetches the stack on GitHub, pulls the branches, and sets up the stack locally. If the stack already exists locally and matches, it switches to the branch.
⚠️ Agent warning: If the local and remote stacks have different branch compositions, this command triggers an interactive conflict-resolution prompt that cannot be bypassed with a flag. To avoid this: run
gh stack unstackfirst to remove the conflicting local stack, then retrygh stack checkout <pr-number>.
When a branch name is provided, the command resolves it against locally tracked stacks only. This is always safe for non-interactive use.
Remove a stack — gh stack unstack
Tear down a stack so you can restructure it — remove a branch, reorder branches, rename branches, or make other large changes. After unstacking, use gh stack init to re-create the stack with the desired structure.
gh stack unstack [flags] [branch]# Tear down the stack (locally and on GitHub), then rebuild
gh stack unstack
gh stack init --base main branch-2 branch-1 branch-3 # reordered
# Older extensions: add --adopt
# Only remove local tracking (keep the stack on GitHub)
gh stack unstack --local
# Specify a branch to identify which stack to tear down
gh stack unstack feature-auth| Flag | Description |
--local | Only delete the stack locally (keep it on GitHub) |
| Argument | Description |
[branch] | A branch in the stack (defaults to the current branch) |
Output conventions
- Status messages go to stderr with emoji prefixes:
✓(success),✗(error),⚠(warning),ℹ(info). - Data output (e.g.,
view --json) goes to stdout. - When piping output, use
2>/dev/nullto suppress status messages if only data output is needed.
Exit codes and error recovery
| Code | Meaning | Agent action |
| 0 | Success | Proceed normally |
| 1 | Generic error | Read stderr for details; may indicate commit/push failure |
| 2 | Not in a stack | Run gh stack init to create a stack first |
| 3 | Rebase conflict | Parse stderr for conflicted file paths, resolve conflicts, run gh stack rebase --continue |
| 4 | GitHub API failure | Check gh auth status, retry the command |
| 5 | Invalid arguments | Fix the command invocation (check flags and arguments) |
| 6 | Disambiguation required | A branch belongs to multiple stacks. Run gh stack checkout <specific-branch> to switch to a non-shared branch first |
| 7 | Rebase already in progress | Run gh stack rebase --continue (after resolving conflicts) or gh stack rebase --abort to start over |
| 8 | Stack is locked | Another gh stack process is writing the stack file. Wait and retry — the lock times out after 5 seconds |
| 9 | Stacked PRs unavailable | The repository does not have stacked PRs enabled. submit will offer to create regular (unstacked) PRs in interactive mode |
Known limitations
- Stacks are strictly linear. Branching stacks (multiple children on a single parent) are not supported. Each branch has exactly one parent and at most one child. If you need parallel workstreams, use separate stacks.
- Stack disambiguation cannot be bypassed. If the current branch is the trunk of multiple stacks, commands error with code 6. Check out a non-shared branch first.
- Multiple remotes require
--remoteor config. If more than one remote is configured, pass--remote <name>or setremote.pushDefaultin git config before runningpush,sync, orrebase. - Merging PRs: Merging Stacked PRs from the CLI is not supported yet. Direct users to open the PR URL in a browser to merge PRs.
- Remote stack checkout requires a PR number.
checkoutwith a branch name only works with locally tracked stacks. Use a PR number (e.g.gh stack checkout 123) to pull stacks from GitHub. - PR title and body are auto-generated. There is no flag to set a custom PR title or body during
submit. The title and body are generated from commit messages plus a footer. Usegh pr editto modify PR title and body after creation.
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.

