TL;DR — On July 30, 2026, GitHub put stacked pull requests into public preview: an ordered chain of dependent PRs where each layer targets the branch below it, reviewers see only that layer’s diff, and when the bottom PR merges, GitHub rebases and retargets everything above it server-side. This is the workflow teams have been faking with “depends on #142” PR descriptions, and hand-rolling with git rebase --onto cascades, for a decade. The native version gets the review model right and kills the worst of the manual pain. It’s still a preview: same-repo only, no GitHub Desktop support, and merge queue integration is still rolling out — so adopt the workflow now, but read the caveats before you bet a release on it.

The pull request I’ve been apologizing for

Every large feature I’ve shipped on the platform has produced one of two bad artifacts. Either a single 1,800-line pull request that no reviewer can hold in their head — schema, write path, API, and UI wiring all in one diff — or a chain of four “small” PRs stitched together with the most fragile piece of infrastructure in software: a sentence in the PR description that says “depends on #142, please review but don’t merge until that lands.”

I’ve written before about what big-bang changes cost in production — most of my worst scaling mistakes started life as a diff too large for anyone to genuinely review. The fix everyone agrees on is smaller PRs. But “make PRs smaller” collides with a real constraint: the layers of a feature depend on each other. The write path needs the schema. The API needs the write path. You can’t open four independent PRs against main when three of them won’t compile without the one below.

So you fake it. You branch off your own branch, open each PR against the previous branch instead of main, and now you’re the maintainer of a tiny distributed system held together by discipline:

git checkout -b feat/wallet-schema main
# ...commit the DDL...
git checkout -b feat/wallet-writes feat/wallet-schema
# ...commit the write path...
git checkout -b feat/wallet-api feat/wallet-writes
# ...commit the API...

# main moved under you? rebase the chain, in order, by hand:
git rebase main feat/wallet-schema
git rebase --onto feat/wallet-schema feat/wallet-schema@{1} feat/wallet-writes
git rebase --onto feat/wallet-writes feat/wallet-writes@{1} feat/wallet-api
git push --force-with-lease origin feat/wallet-schema feat/wallet-writes feat/wallet-api

Git 2.38 made the local half of this less miserable with git rebase --update-refs, which drags the intermediate branch pointers along in one rebase. But Git only ever fixed the local half. GitHub — the place where the review actually happens — had no idea these four PRs were one unit of work. That’s the gap that just closed.

What stacked pull requests actually are

A stacked pull request is one PR in an ordered, dependent series: the bottom PR targets main, and each PR above it targets the branch of the one below. GitHub now understands the whole chain as a stack — each PR reviews independently and shows only its own layer’s diff, and the stack merges bottom-up, together or in parts.

            ┌────────────────────────────────┐
  layer 4   │ PR #145 · admin UI wiring      │ → targets feat/wallet-api
            ├────────────────────────────────┤
  layer 3   │ PR #144 · balance read API     │ → targets feat/wallet-writes
            ├────────────────────────────────┤
  layer 2   │ PR #143 · ledger write path    │ → targets feat/wallet-schema
            ├────────────────────────────────┤
  layer 1   │ PR #142 · wallet schema (DDL)  │ → targets main
            └────────────────────────────────┘

None of this shape is new. The stacked-diff model is how Meta and Google have reviewed code internally for years, and an entire tool ecosystem — Graphite, ghstack, git-branchless, Sapling — grew up specifically to bolt it onto GitHub from the outside. What’s new is that the model is now native to github.com: visible in the PR page as a stack map, enforced by the merge box, and available in every repository without asking your whole team to install anything.

The rule for slicing layers is the one the GitHub docs state plainly, and it’s the same rule I’d give for slicing anything: if code in one layer depends on code in another, the dependency must live in the same layer or a lower one. Schema below writes, writes below reads, reads below UI. If you can’t order two changes, they belong in the same layer.

The mechanics that actually matter

Four behaviors turn this from a diagram into a workflow. These are the things the hand-rolled version could never do.

1. Merging the bottom retargets everything above it — on GitHub’s servers. Merge PR #142 and GitHub rebases the remaining branches automatically, so #143 now targets main and the layers above it stay attached. In the manual workflow, this exact moment was the most dangerous ten minutes of the week; now it’s nothing. Cascading rebases can also be triggered from the PR page or via the CLI whenever main moves.

2. You can land the stack in one operation, or in parts. Merging the top PR lands every unmerged layer below it in a single action. Merging a mid-stack PR lands it and everything beneath, and the layers above retarget automatically. Merge commits, squash merges, and rebase merges are all supported — remember that detail, because squash merges are what made the manual version blow up.

3. Protections apply to every layer, not just the bottom. This was my first question, because a mid-stack PR technically targets a feature branch, and feature branches usually have no protection at all. GitHub’s answer: the merge requirements for every PR in the stack are determined by the bottom PR’s base branch. CODEOWNERS approvals, required checks, and branch protection rules are enforced on every layer, and CI that would run for a PR against main runs for all of them. A stack is not a loophole.

4. Reviewers see one layer at a time. Each PR shows only its own diff, with a stack icon, its layer number, and a stack map in the merge box for jumping between layers. Four 200-line reviews genuinely happen; one 800-line review gets skimmed and rubber-stamped. There’s decent evidence that defect-detection falls off a cliff beyond a few hundred lines per review, which is the entire argument for stacking in one sentence.

The local workflow lives in a CLI extension:

gh extension install github/gh-stack

gh stack handles the part Git alone can’t: creating and tracking branches in dependency order, keeping the chain rebased, pushing all of it, opening the linked PRs, and navigating between layers. It’s also exposed as a skill to GitHub Copilot and other coding agents — GitHub’s own engineering blog has a nice write-up on using it to split one giant AI-generated PR into a reviewable stack, which I suspect is half the reason this feature finally got prioritized.

Native stacks vs. hand-rolling vs. Graphite

Hand-rolled branch chainThird-party tools (Graphite, ghstack)GitHub native stacks
Rebase after bottom mergesYou, locally, branch by branchAutomated by the toolAutomatic, server-side
Per-layer diff for reviewersBreaks the moment a lower branch mergesYes, in the tool’s UIYes, on github.com
Land whole stack at onceNo — merge, wait, retarget, repeatVaries by toolOne operation from any layer
Protections on mid-stack PRsNo — they target unprotected branchesVariesEnforced on every layer
Team has to install anythingNo, but everyone suffersYes, tool adoption per personNo — reviewers just use GitHub
Cross-fork stacksPossible, painfullyMostly noNo

The honest read on the third-party column: tools like Graphite still offer things the preview doesn’t (their own review UI, analytics, opinionated CLI ergonomics), and teams already happy on them have no urgent reason to move. But the default answer to “how do we do stacked diffs on GitHub” used to be “adopt an external tool as a team,” and that answer just changed to “turn on the preview.”

What actually broke when I hand-rolled this

I want to be precise about my experience here: I haven’t run the native feature through a production release cycle yet — it’s been public for two weeks. What I have done is run the hand-rolled version for years, and every scar from that maps directly onto something the native feature was built to fix.

Squash merges broke the chain every single time. The platform’s repos squash-merge into main, which means the commits from layer 1 land as one brand-new commit with a new SHA. Layer 2 still contains the original commits, so rebasing it onto main replays changes that are already there — conflict after conflict on code that was already reviewed and merged. I eventually kept a checklist for the post-merge rebase cascade. A checklist, for merging my own approved work. Native stacks doing the retarget server-side, with squash merges explicitly supported, deletes this entire failure class.

Force-pushes kept torching review context. Every cascade ended in git push --force-with-lease on three branches, and GitHub would mark reviewer comments as outdated on all of them. A colleague once re-reviewed 600 lines they had already approved because the diff view lost track of what had actually changed versus what had merely been rebased. After the second time, they reasonably asked me to stop stacking and just send the big PR — the workflow was punishing the exact people it was supposed to help.

“Don’t merge yet” is not access control. The dependency between my PRs lived in prose. It worked until the afternoon someone helpfully merged a mid-stack PR into its feature branch parent, the parent then merged into main days later carrying an unreviewed-in-context change, and we spent an hour reconstructing which approval covered what. The order of a stack has to be enforced by the system, and now it is: pull requests in a native stack merge bottom-up because GitHub refuses anything else.

Where I’d still be careful

This is a public preview, and GitHub says plainly that it’s subject to change. Reading the docs with a skeptic’s eye, four things would shape my rollout:

  1. Merge queue support is still arriving. It was announced as rolling out “over the coming weeks” after the preview launch. If your repo gates main behind a merge queue — and if you care about stacks, you probably do — verify the integration works in your repo before you route a real feature through it.
  2. Same repository only. Cross-fork stacks aren’t supported, so open-source contributors working from forks are outside this workflow entirely for now.
  3. The API path is different. Merging stacks programmatically requires the asynchronous merge API. If you have bots or release automation that merge PRs via the REST API today, they need updating before they meet their first stack.
  4. No GitHub Desktop support, which matters exactly as much as your team uses GitHub Desktop.

There’s also a judgment call no tool makes for you: how thick a layer should be. Stacks make small PRs cheap, and the failure mode on the other side is real — fifteen-line layers where the reviewer needs five PRs’ worth of context to evaluate any one of them. My working rule is that a layer should be one decision (the schema, the write path, the rollout switch), not one file. It’s the same instinct as expand/contract deploys: each step ships alone, works alone, and never breaks the layer below it.

And the broader lesson I keep relearning about adopting anything at this stage: standardized and deployable are different dates. I went through this with the HTTP QUERY method — the design was right long before the ecosystem could carry it. Native stacks are earlier on that curve than the announcement excitement suggests. The workflow is proven; this implementation of it is two weeks old.

FAQ

What are stacked pull requests on GitHub? An ordered series of dependent pull requests in the same repository, where the bottom PR targets the default branch and each PR above targets the branch below it. GitHub treats the chain as a stack: each PR is reviewed against only its own layer’s diff, merges happen bottom-up, and higher layers rebase automatically when lower ones land.

How do I create a stacked pull request? Branch off your previous branch instead of main, then open each PR against the branch below it — on github.com, the mobile app, or the CLI. The gh stack extension (gh extension install github/gh-stack) manages the local side: it tracks branches in dependency order, keeps them rebased, pushes the chain, and opens the linked PRs.

What happens when I merge the bottom PR of a stack? GitHub rebases the remaining branches on its own servers and retargets the next PR at the default branch. The manual rebase cascade — git rebase --onto per branch followed by force-pushes — is no longer your job.

Do branch protection rules apply to mid-stack pull requests? Yes. Merge requirements for every PR in a stack are determined by the bottom PR’s base branch, so CODEOWNERS approvals, required checks, and protection rules are enforced on every layer, including PRs that target a feature branch rather than main.

Do stacked pull requests work with squash merges? Yes — merge commit, squash, and rebase merge methods are all supported, and GitHub handles the retargeting that squash merges used to break in hand-rolled stacks, where re-written SHAs forced conflict-ridden rebases onto already-merged code.

Can I stack pull requests across forks? No. All branches in a stack must live in the same repository, which keeps the typical open-source fork-based contribution flow outside this feature for now.

Do I still need Graphite or ghstack? If your team already runs one happily, there’s no forced migration — those tools still have their own review UIs and ergonomics. If you avoided stacked diffs because adopting a third-party tool team-wide was the price, that price just dropped to zero.

Is the feature generally available? No — public preview as of July 30, 2026, rolling out to all repositories, with merge queue support following over subsequent weeks. Preview features can change; validate in a low-stakes repo before making stacks your team’s default.


The one idea to take away

The unit of review was never meant to be “whatever accumulated on the branch.” It’s a layer: one decision, small enough to actually read, ordered so it can’t land before what it depends on. Teams have known this for a decade and paid for it either in unreviewable mega-PRs or in rebase cascades and “depends on #142” comments. GitHub’s stacked pull requests make the layer the first-class unit — the server does the retargeting, the merge box enforces the order, and the reviewer finally sees one decision at a time. Learn the slicing discipline now; that skill transfers even if the preview shifts under you.