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 times | Break 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 changes | Only 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 early | Merge the first PR in the stack; the rest stay pending until they’re ready |
| 需要提前发布大型变更的一部分 | 合并堆叠中的第一个 PR;其余部分保持挂起,直到准备就绪 |
| CI resources | Only 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 / Service | Key Features | Installation / Setup | Typical Workflow |
|---|---|---|---|
| ghstack (GitHub CLI plugin) | Creates stacked PRs automatically; handles base-branch updates; works with GitHub’s GraphQL API. | pip install ghstack | ghstack push |
| ghstack (GitHub CLI 插件) | 自动创建堆叠式 PR;处理基础分支更新;集成 GitHub GraphQL API。 | pip install ghstack | ghstack push |
| GitTown | git town ship can ship a stack of dependent branches in order. | brew install git-town | git town new featureA |
| GitTown | git town ship 可以按顺序发布一系列依赖分支。 | brew install git-town | git town new featureA |
| gstack | Lightweight Bash script for sequential commits. | curl ... | gstack create . |
| gstack | 用于顺序提交的轻量级 Bash 脚本。 | curl ... | gstack create . |
| GitHub Draft PR + labels | No 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