Stacked pull requests: how to set up and review a stack on GitHub
Stacked pull requests split a large change into small layers. We look at GitHub’s built-in support and at how to review code in a stack.
Summary. Stacked pull requests split a large change into small pull requests that build on one another. GitHub put the feature into public preview on 30 July 2026 and made it generally available on 6 October 2026. On 14 October 2026 we read GitHub’s announcements, its documentation and the guide to the gh stack extension. We add what we learned building a stack by hand in our own repository, before the built-in support arrived.
- Each layer is its own pull request. The bottom one targets the trunk, each of the others targets the branch of the one below; each shows only its own layer’s diff.
- Every layer follows the trunk’s rules. Required approvals, required checks and CODEOWNERS apply even when the pull request does not target
maindirectly. - You merge from the bottom up. The pull request you pick is merged together with the ones below it in a single operation; the ones above it are rebased automatically and then target the trunk.
- Verify which commit your checks ran on. In the stack we built by hand, the green checks belonged to an old commit; after a rebase, compare that commit with the tip of the branch.
What a stack is and why it helps
When you open a large feature as one pull request, the reviewer sees hundreds of lines at once. Stacked pull requests split the same work into a sequence of small pull requests. The sequence is called a stack, and each pull request in it is a layer.
As GitHub defines it, a stack is two or more pull requests in the same repository. The bottom one targets the stack’s trunk, which is usually main but can also be a release branch. Each pull request above it targets the branch of the one below. The branch a pull request targets is its base.

Each pull request shows only its own layer’s diff: the difference between its branch and the branch below it. The order follows one rule: the code a layer depends on lives in the same branch or a lower one. Shared types and the database schema go at the bottom; the API endpoints and the UI that use them go on top.
This helps in two ways. According to GitHub’s documentation, a small pull request gets reviewed faster and is less likely to be skimmed, go stale or run into conflicts. And if your next change depends on work that has not been merged yet, you do not have to wait for it: you open a new pull request on top. If an AI agent writes the code, the order comes naturally: one layer per task.
Chaining branches by hand is not new; what is new is that GitHub recognises the chain. The feature entered public preview on 30 July 2026 and became generally available on 6 October 2026; according to the announcement, it is available on every github.com plan.
We describe what the feature does from GitHub’s own documentation, as we read it on 14 October 2026. We build diffox, a tool that reviews pull requests; before the built-in support arrived, we built a stack by hand in our own repository. What we learned there is in a separate section below.
How to set up a stack on GitHub
On the command line, use the gh stack extension for GitHub CLI. It creates the branches in the right order, rebases them, pushes them, opens the pull requests and links them into a stack. Here is how to set up a three-layer stack:
gh extension install github/gh-stack
gh stack init auth-layer # first branch, on top of the trunk
git add .
git commit -m "Authentication layer"
gh stack add api-endpoints # second branch, on top of the first
git add .
git commit -m "API endpoints"
gh stack add frontend # third branch
git add .
git commit -m "Frontend"
gh stack submit # pushes, opens the pull requests, links them as a stack
gh stack view # shows the branches, the pull requests and their statusgh stack submit opens each pull request with the right base: the first branch targets main, and each later branch targets the one below it. If your trunk is not main, run gh stack init --base release auth-layer. The extension is optional; you can set up the same stack in other ways:
- Web interface. Open the first pull request as usual. For the second one, set the base to the first one’s branch and select the “Create stack” option. If you already have open pull requests whose bases form a chain, GitHub notices and shows a banner offering to turn them into a stack.
- Coding agent.
gh skill install github/gh-stackinstalls the skill that teaches an agent to work withgh stack; GitHub’s example is Copilot. - Other tools. If you manage your branches with Jujutsu, Sapling or git-town, the
gh stack linkcommand opens the same branches as a stack on GitHub.
The page of a pull request in a stack shows a stack map. It lists every pull request in the stack with its status and takes you to any layer in one click; the trunk is at the bottom of the map.
How branch protection rules and CI work in a stack
Rules were the weak spot of chaining branches by hand. The upper layers target a feature branch, not main, and GitHub’s documentation says that without built-in support, branch protection rules and CI checks often trigger only on the bottom pull request.
In a built-in stack, every pull request is evaluated against the rules of the stack’s trunk, whichever branch it targets directly. The reference page lists four rules: required review approvals, required status checks, CODEOWNERS and code scanning.
GitHub Actions follows the same logic. A workflow triggered by pull_request events targeting main runs for every pull request in the stack; you do not have to change the workflow file.
Keep an eye on CI usage: a workflow runs once per pull request, so a large stack multiplies it. So that you can limit expensive jobs to certain layers, the stack’s details are available in workflow expressions, as the documentation describes: github.event.pull_request.stack holds the stack’s size (size) and the pull request’s position in it (position). When the two are equal, you are on the top layer.
How to merge a stack
A stack is merged from the bottom up. You can merge several pull requests at once, as long as they form an unbroken run starting from the lowest one not yet merged. A pull request in the middle cannot be merged on its own; the ones below it are merged with it.

According to the documentation, a pull request can be merged when three conditions hold: it meets every protection requirement of the trunk, so does every pull request below it, and the history between the branches is linear. If a lower branch gets a new commit or the trunk moves ahead, the history is no longer linear. A “Rebase stack” button then appears in the merge box; on the command line, the equivalent is gh stack rebase followed by gh stack push.
All three merge methods are supported: merge commit, squash and rebase. With squash, each pull request becomes one commit on the trunk; three pull requests, three commits. After a merge, the next pull request is rebased automatically and targets the trunk directly. gh stack sync --prune updates your local branches: it moves the trunk forward, rebases the remaining branches onto it and deletes the merged local branches.
In repositories that use a merge queue, the pull requests in a stack enter the queue in the right order. If one is removed from the queue, the ones above it are removed too.
When we built a stack by hand, we got stuck in three places
In August 2026, before the built-in support arrived, we built a two-layer stack by hand in our own repository, which merges with squash. Once the bottom pull request was merged, we had to do three things by hand for the top one.

The first was the rebase. A squash turns the lower branch’s commits into one new commit; the old commits are not part of the trunk’s history. The top branch still carried those commits, so a plain merge with the trunk ran into conflicts. git rebase --onto fixed it by moving only the top pull request’s own commits. The second was the base: the top pull request kept targeting the lower branch, and we switched it to the trunk by hand.
The third was silent. Neither the force-push nor the change of base started CI for the rebased tip. The green marks on the page belonged to checks that had run on the previous tip. CI only started once we closed the pull request and opened it again.
# the bottom pull request was merged with squash; you are on the top branch
git fetch origin
git rebase --onto origin/main <old-tip-of-lower-branch>
git push --force-with-lease
# switch the top pull request’s base to the trunk
gh pr edit 123 --base main
# is the commit the checks ran on the same as the branch tip
gh pr view 123 --json headRefOid
gh run list --branch api-endpoints --json headSha,workflowName,conclusionWe hit a similar trap on another pull request. When the pull request conflicted with its base, GitHub did not create the merge commit that workflows run on, and ten of the eleven checks never started. The page still read “All checks have passed · 1 successful check”, because the one check that ran did not need that commit. GitHub’s documentation states the rule: on a pull request with a conflict, pull_request workflows do not run.
What GitHub now does for you
Here is how those steps compare with GitHub’s documentation.
| Topic | Chain of branches built by hand | GitHub’s built-in stack |
|---|---|---|
| The upper branch, once the lower layer is merged | Rebased by hand; after a squash, it needs git rebase --onto | Rebased automatically |
| The upper pull request’s base | Switched to the trunk by hand | Switches to the trunk automatically |
| Branch protection rules and CI | Often trigger only on the bottom pull request | Evaluated against the trunk on every layer |
| Checks after a rebase | Did not run again for us; the old commit’s result showed | Re-triggered after “Rebase stack” and gh stack push |
In the “Chain of branches built by hand” column, the rebase, base and checks rows come from our own experience and the rules row from GitHub’s documentation. The “GitHub’s built-in stack” column comes from GitHub’s documentation, 14 October 2026.
According to the documentation, GitHub now handles the rebase and the base. On squash, gh stack’s own documentation describes what we saw: after a squash, the old commits are not in the trunk’s history; gh stack sync detects this and rebases with --onto.
On checks, the documentation names two cases: CI runs again after the “Rebase stack” button and after gh stack push. For the automatic rebase that follows a partial merge, we could not find the same statement in the documentation on 14 October 2026. So before you merge an upper layer, it is worth checking these four things.

How to review a stack
With a stack, you do not review one large diff but several small ones, each against the layer below it. That changes three things for the reviewer.
- Start at the bottom. When the layers are tightly coupled, GitHub advises asking for reviews from the bottom up: a mistake in the bottom layer carries into every branch above it. If different people review the layers, they can work in parallel.
- Do not look for a lower layer’s code in an upper layer’s diff. If a function the third layer calls was defined in the first layer, it is not in the diff, and not in
mainyet either. It is in the branch you are reviewing, though; the stack map takes you to that layer’s pull request. - Put the finding on the layer it belongs to. According to the documentation, the fix goes on the branch the change belongs to, and the branches above are then rebased. If the diff does not change, the rebase keeps existing approvals.
gh stack checkout auth-layer # the layer the fix belongs to
git add .
git commit -m "Handle the expired token case"
gh stack rebase --upstack # sets the branches above on top of this commit
gh stack push # pushes the branches with --force-with-leaseThese rules hold for a human reviewer and an AI review tool alike: both read the layer’s diff. Approving one layer does not approve the ones below it; each pull request needs its own required approval and checks.
Not every change needs a stack
A stack is for work that builds on itself and is too large to review in one sitting. In these cases, one pull request or several independent ones work better:
- The change is small. Splitting a diff that can be read in one sitting only makes the reviewer open more pages.
- The changes do not depend on each other. A stack is a single linear chain: each branch has one below it and at most one above it. An unrelated fix goes in its own pull request.
- The contribution comes from a fork. All branches must be in the same repository; stacks across forks are not supported.
- CI is expensive. Each layer runs its own checks; limit the expensive jobs to certain layers first.
The documentation we read on 14 October 2026 lists three more limits. GitHub Desktop does not support stacks. Tools that merge through the API have to move to the asynchronous merge API. On auto-merge, two pages say different things: the merge documentation says it is not supported for stacks, while the 6 October announcement says it will roll out over the coming weeks.
diffox reviews the diff of the pull request it is given. In a stack every layer is a separate pull request, so each one is reviewed separately and its findings are written on that layer’s pull request.
Frequently asked questions
What is a stacked pull request?
Stacked pull requests are a way of splitting a large change into small pull requests that build on one another. The bottom pull request targets the trunk, usually main; each pull request after it targets the branch of the one below. Each shows only its own layer’s diff and is reviewed separately.
How do you create a stacked pull request on GitHub?
On the command line, install the extension with gh extension install github/gh-stack. gh stack init creates the first branch and gh stack add the branches on top of it; gh stack submit opens the pull requests and links them into a stack. In the web interface, give the first pull request’s branch as the second one’s base and select the “Create stack” option. All branches must be in the same repository.
What is gh stack?
gh stack is the GitHub CLI extension, published by GitHub, that manages stacks. It creates the branches in the right order, runs cascading rebases, pushes, opens the pull requests and lets you move between layers. It is optional; you can also set up a stack from the web interface.
Are stacked pull requests still in public preview?
No. GitHub announced the feature in public preview on 30 July 2026 and made it generally available on 6 October 2026. According to the announcement, it is available on every github.com plan and will be included in an upcoming GitHub Enterprise Server release.
What happens to the pull requests above once the bottom one is merged?
According to GitHub’s documentation, they stay open; the next pull request is rebased automatically and targets the trunk directly. All three merge methods are supported, squash included. gh stack sync updates your local branches; it recognises the state after a squash and rebases with --onto.
How do CI and branch protection rules work with stacked pull requests?
Every pull request in a stack is evaluated against the rules of the stack’s trunk, whichever branch it targets directly: required approvals, required checks and CODEOWNERS apply on every layer. pull_request workflows targeting main run for every layer. For a layer to be merged, every layer below it must meet the requirements too.
Does diffox review stacked pull requests?
diffox reviews the diff of the pull request it is given. Every layer in a stack is a separate pull request, so each layer is reviewed by its own diff. It does nothing special for stacks, and no setting is needed.