Github Stacked PR

Github Stacked PR

🎯 What a “Stacked PR” Is (and Why You’ll Want One)

A stacked pull request (sometimes called a stacked PR, stacked diff, or dependent PR) is a series of PRs that build on top of each other, each one containing a small, logically‑isolated change.

🎯 什么是“堆叠式 PR”(以及为什么你需要它)

堆叠式 Pull Request(有时称为 Stacked PR、Stacked Diff 或依赖型 PR)是一系列相互叠加的 PR,每一个 PR 都包含一个小的、逻辑上独立的变更。

main ──► A ──► B ──► C
         │    │    │
         │    │    └─ PR‑C (depends on B)
         │    └─ PR‑B (depends on A)
         └─ PR‑A (directly on main)

A is based on main. B is based on A (its head). C is based on B, etc. When you eventually merge the stack in order (A → B → C), each change lands cleanly, and reviewers can focus on one cohesive piece at a time.

A 基于 main 分支。B 基于 A(其头部)。C 基于 B,依此类推。当你最终按顺序合并整个堆叠(A → B → C)时,每个变更都能干净地合入,且审查者可以一次专注于一个连贯的部分。

Why Stack PRs? / 为什么要使用堆叠式 PR?

Problem / 问题Stacked PR Solution / 堆叠式 PR 解决方案
Huge, monolithic PRs that are hard to review & cause long CI timesBreak the work into bite‑size PRs (e.g., “feature flag”, “data model”, “UI”)
庞大且难以审查的单体 PR,导致 CI 时间过长将工作拆分为小块 PR(例如:“功能开关”、“数据模型”、“UI”)
Inter‑dependent changes (e.g., a new API + its consumer)Each dependent change lives in its own PR, but they still get tested together because they are built on top of each other
相互依赖的变更(例如:新 API + 其调用方)每个依赖变更都有自己的 PR,但由于它们是相互叠加的,因此仍能一起进行测试
Rebasing on main constantly drags in unrelated changesOnly the bottom PR needs to be rebased onto main; the rest stay on top of it
频繁在 main 上进行变基(rebase)会引入不相关的变更只有最底层的 PR 需要 rebase 到 main,其余 PR 保持在它之上
Need to ship part of a larger change earlyMerge the first PR in the stack; the rest stay pending until they’re ready
需要提前发布大型变更的一部分合并堆叠中的第一个 PR;其余部分保持挂起,直到准备就绪
CI resourcesOnly the bottom PR runs the full suite against main; higher PRs can run a lighter subset because they already passed lower‑level tests
CI 资源消耗只有最底层的 PR 针对 main 运行完整测试套件;上层 PR 可以运行较轻量的子集,因为它们已经通过了底层测试

📦 The Landscape of Tools (as of 2026)

📦 工具生态概览(截至 2026 年)

Tool / ServiceKey FeaturesInstallation / SetupTypical Workflow
ghstack (GitHub CLI plugin)Creates stacked PRs automatically; handles base-branch updates; works with GitHub’s GraphQL API.pip install ghstackghstack push
ghstack (GitHub CLI 插件)自动创建堆叠式 PR;处理基础分支更新;集成 GitHub GraphQL API。pip install ghstackghstack push
GitTowngit town ship can ship a stack of dependent branches in order.brew install git-towngit town new featureA
GitTowngit town ship 可以按顺序发布一系列依赖分支。brew install git-towngit town new featureA
gstackLightweight Bash script for sequential commits.curl ...gstack create .
gstack用于顺序提交的轻量级 Bash 脚本。curl ...gstack create .
GitHub Draft PR + labelsNo external tool; use depends-on:<PR#> label.Enable in org settings.Create PR-A → PR-B, add label.
GitHub 草稿 PR + 标签无需外部工具;使用 depends-on:<PR#> 标签。在组织设置中启用。创建 PR-A → PR-B,添加标签。

Bottom-line: If you just need a quick, “no-install” solution, the built-in draft-PR + depends-on label works fine. If you want to automate the entire stack lifecycle, ghstack is the most mature and GitHub-native option in 2026.

总结: 如果你只需要一个快速、“无需安装”的方案,内置的草稿 PR + depends-on 标签就足够了。如果你想自动化整个堆叠生命周期(创建、变基、更新、合并),ghstack 是 2026 年最成熟且最符合 GitHub 原生体验的选择。


🛠️ Step-by-Step Guide Using ghstack

🛠️ 使用 ghstack 的分步指南(最受欢迎的选择)

Below is a complete workflow you can copy-paste into a terminal. It assumes you have: Git 2.40+, GitHub CLI (gh), and Python 3.9+.

以下是一个可以复制到终端的完整工作流。前提条件:已安装 Git 2.40+、GitHub CLI (gh) 并已完成认证,以及 Python 3.9+。

1️⃣ Install the tools / 安装工具

brew install gh
pip install --user ghstack

2️⃣ Prepare a branch and make a series of commits / 准备分支并进行一系列提交

git checkout main
git pull origin main
git checkout -b feature/stacked

# 1️⃣ First logical change / 第一个逻辑变更
echo "def hello(): return 'world'" > hello.py
git add hello.py
git commit -m "feat: add hello() helper"

# 2️⃣ Second logical change / 第二个逻辑变更
cat >> hello.py <<'EOF'
def greet(name): return f"Hello, {name}! " + hello()
EOF
git add hello.py
git commit -m "feat: add greet() that uses hello()"

# 3️⃣ Third logical change / 第三个逻辑变更
mkdir -p tests
cat > tests/test_hello.py <<'EOF'
import unittest
from hello import greet
class TestHello(unittest.TestCase):
    def test_greet(self): self.assertIn("Hello, Alice!", greet("Alice"))
EOF
git add tests/
git commit -m "test: add unit tests for greet()"

3️⃣ Push the stack to GitHub / 将堆叠推送到 GitHub

ghstack push

4️⃣ Review & Iterate / 审查与迭代

Reviewers see each PR separately. CI runs on each branch. If you need to amend the second commit: 审查者会分别看到每个 PR。CI 会在每个分支上运行。如果你需要修改第二个提交:

git checkout ghstack/2
# ... make changes ...
git commit --amend
ghstack push