Skip to main content

What are Stacked PRs?

Stacked pull requests split one larger change into an ordered chain of dependent reviews.

Introduction

In a stacked pull-request workflow, each branch builds on the branch below it. Each pull request targets its immediate parent branch, so reviewers see the increment introduced by that layer instead of the full change from main.

This makes a large feature reviewable before every layer is complete. The cost is maintaining the dependencies as lower layers change and merge.

Understanding the Concept

A stacked pull request is one pull request in an ordered chain. The bottom layer targets main. Every higher layer targets the branch directly below it.

Definition

Stacked Pull Request

A pull request whose branch depends on another pull-request branch, forming an ordered chain of incremental changes.

Definition

Stack Root

The lowest branch in a pull-request stack, usually the only layer that targets the main branch directly.

For example:

main
└── auth/schema PR 1: auth/schema -> main
└── auth/service PR 2: auth/service -> auth/schema
└── auth/api PR 3: auth/api -> auth/service

If auth/schema changes during review, the branches above it still contain commits based on the old version. Rebasing each dependent branch in order is a restack.

Definition

Restack

The process of rebasing dependent branches in order after a lower branch or the target branch changes.

The pull requests are independently reviewable, but the branches are not independent. A higher layer cannot be merged safely until its required lower layers are available on the target branch.

Applying It in Practice

Create three layers:

git switch main
git pull --ff-only

git switch -c auth/schema
# edit and commit

git switch -c auth/service
# edit and commit

git switch -c auth/api
# edit and commit

Open pull requests with these base branches:

auth/schema -> main
auth/service -> auth/schema
auth/api -> auth/service

After changing the bottom layer, restack from bottom to top:

git switch auth/service
git rebase auth/schema

git switch auth/api
git rebase auth/service

git push --force-with-lease origin auth/service auth/api

Before pushing, inspect each layer against its intended base:

git log --oneline auth/schema..auth/service
git diff auth/schema...auth/service

After the bottom pull request merges, retarget the next pull request to main if the hosting platform or stack tool does not do it. The exact diff can change when the platform squash-merges or rebases the lower layer because the merged commits have different identities. Restacking the remaining branches onto updated main restores a clear chain.

Engineering Considerations

Use a stack when the feature has ordered layers with clear review boundaries. Schema, domain logic, and API changes can form a useful stack when each layer is testable and leaves the target branch in a valid state.

Do not create a stack for a small change or split code at arbitrary file boundaries. Reviewers should be able to explain what one layer does without reading all later layers.

Keep stacks shallow. Two or three stable layers are manageable by hand. Deep stacks with frequent changes near the root create repeated conflict resolution and force pushes. Stack-aware tools can automate branch bookkeeping and pull-request retargeting, but they cannot choose sound boundaries or resolve semantic conflicts.

Merge order matters. Land layers from the root upward. If a project uses squash merge, expect the lower layer's commit identity to change on main and restack the remaining branches.

Scaling and Operations

Assign one owner to maintain the branch chain, even when several developers contribute. That owner coordinates restacks, verifies pull-request bases, and tells reviewers when a diff changed after a force push.

Automate these checks:

  • every layer has the expected base branch
  • commits in one layer do not appear unexpectedly in another
  • CI runs for each incremental diff and for the combined stack
  • force pushes use leases
  • merged layers are retargeted or removed

Review the combined result as well as each layer. Individually correct diffs can still produce a broken integration when assumptions differ across layers.

Avoid dependencies on branches owned by another team unless both teams agree on rewrite policy. A force push to a lower layer changes every dependent branch's base.

Next Steps