把 AI 生成的巨型 PR 拆成可审查的 GitHub PR 栈

2026-08-05 51 预计阅读时间: 1 分钟
来源: github.blog AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:9 分钟

编码代理很容易一次生成数千行改动,但“代码能运行”不等于“改动能审查”。当数据库迁移、领域模型、API、界面和测试全部塞进一个 Pull Request,审查者很难区分基础设施变更与业务行为,也难以判断某段代码究竟依赖什么。

更实用的做法,是在任务开始前就要求代理把工作拆成一组有顺序的分支,并在 GitHub 上建立彼此依赖的 stacked pull requests(堆叠式 PR)。每个 PR 只表达一个清晰决策,后续 PR 以上一个分支为基础。

PR 栈解决的不是行数,而是依赖关系

假设要为订单系统增加“取消订单”功能,可以拆成四层:

  1. cancel/domain:增加订单状态与状态转换规则。
  2. cancel/storage:增加数据库字段和持久化逻辑,依赖领域模型。
  3. cancel/api:暴露取消订单接口,依赖存储层。
  4. cancel/ui:增加取消按钮和交互,依赖 API。

对应的 GitHub PR 基线应当形成一条链:

cancel/domain  -> main
cancel/storage -> cancel/domain
cancel/api     -> cancel/storage
cancel/ui      -> cancel/api

这样,审查 cancel/api 时,GitHub 展示的是 API 分支相对 cancel/storage 新增的内容,而不是整个功能从 main 开始的全部差异。每一层都可以独立讨论、修改和测试。

拆分边界应围绕依赖和行为,而不是机械地限制文件数量。一个包含模型实现及其单元测试的 PR,通常比“所有生产代码一个 PR、所有测试另一个 PR”更容易验证。

先让代理提交拆分方案

不要只给编码代理一句“实现取消订单”。可以先要求它输出分支计划,并明确禁止在计划确认前修改代码。下面的提示词可以直接改造:

你正在一个 GitHub 仓库中实现“取消订单”功能。

在修改代码前:
1. 阅读相关模型、数据库迁移、API、前端和测试。
2. 将工作拆成 3 到 5 个按依赖顺序排列的 PR。
3. 每个 PR 必须可单独审查,并包含与该层行为对应的测试。
4. 为每层列出:分支名、目标基线分支、改动范围、验证命令。
5. 不要按文件类型拆分;按可验证的行为和依赖边界拆分。
6. 等计划确认后,再逐层实现并提交。

实现阶段要求:
- 每个分支只包含该层新增的提交。
- 提交信息说明行为变化,不使用“misc changes”之类的描述。
- 不重写已经进入审查的分支,除非明确得到允许。
- 完成每层后运行对应测试,并生成 PR 标题和正文。

这一步的价值在于提前暴露错误边界。例如代理可能把数据库迁移放在 UI 分支中,或者让基础模型依赖尚未出现的 API 类型。此时调整计划,成本远低于在一个巨大 PR 中重新整理提交历史。

用 Git 和 GitHub CLI 建立一个 PR 栈

下面示例假设仓库已配置 origin,本机安装并登录了 GitHub CLI。请把测试命令和分支名称替换成项目实际内容。

set -euo pipefail

git switch main
git pull --ff-only origin main

# 第 1 层:领域规则
git switch -c cancel/domain
# 在这里实现领域模型和单元测试
npm test -- --runInBand domain

git add -A
git commit -m "Add order cancellation domain rules"
git push -u origin cancel/domain

gh pr create \
  --base main \
  --head cancel/domain \
  --title "Add order cancellation domain rules" \
  --body "Introduces cancellation states, transition rules, and domain tests."

# 第 2 层从第 1 层继续,而不是重新从 main 开始
git switch -c cancel/storage
# 在这里增加迁移和持久化实现
npm test -- --runInBand storage

git add -A
git commit -m "Persist order cancellation state"
git push -u origin cancel/storage

gh pr create \
  --base cancel/domain \
  --head cancel/storage \
  --title "Persist order cancellation state" \
  --body "Adds the schema migration and persistence behavior on top of the domain changes."

# 第 3 层继续依赖第 2 层
git switch -c cancel/api
# 在这里实现接口和集成测试
npm test -- --runInBand api

git add -A
git commit -m "Expose order cancellation API"
git push -u origin cancel/api

gh pr create \
  --base cancel/storage \
  --head cancel/api \
  --title "Expose order cancellation API" \
  --body "Adds the cancellation endpoint and API tests; depends on the storage PR."

创建完成后,应在每个 PR 的正文中标出栈顺序,例如:

## Stack

1. `cancel/domain` <- current base
2. `cancel/storage` <- this PR
3. `cancel/api`

## Verification

```bash
npm test -- --runInBand storage
实际 PR 正文中的嵌套代码块可以按仓库模板调整。关键是让审查者立即知道当前层的基线、后续依赖和验证方式。

## 合并顺序与历史重写

PR 栈通常从底部开始合并,也就是先合并最接近 `main`  PR。基础层进入 `main` 后,把下一层的 base 改成 `main`

```bash
gh pr edit 123 --base main

这里需要提前决定合并策略。如果使用普通 merge commit,祖先关系通常能保留下来,后续 PR 更容易重新设置 base。如果仓库强制 squash merge,合并后的提交身份会改变,后续分支可能需要 rebase。以 cancel/storage 为例,可以这样实践:

git fetch origin
git switch cancel/storage

git rebase --onto origin/main origin/cancel/domain cancel/storage
git push --force-with-lease origin cancel/storage

gh pr edit 123 --base main

--force-with-lease 仍然会改写远端历史,只应在确认没有其他人向该分支推送后使用。更深的分支也要跟随新的父分支进行 rebase,因此栈越长,维护成本越高。多数团队把栈控制在 3 到 5 层会更容易管理;更复杂的变更可以拆成多个相对独立的栈。

落地时检查这几件事

采用 PR 栈时,可以用以下标准约束代理和人工提交:

  • 每个 PR 都有一句能够独立说清楚的行为描述。
  • 测试与对应实现处于同一层,而不是集中到栈顶。
  • 后续分支只依赖前一层,不跨层引用尚未出现的代码。
  • PR 正文列出整个栈,并标明当前 PR 的位置。
  • CI 对每个分支运行,不能只在最后一层获得绿色结果。
  • 合并前明确采用 merge、rebase 还是 squash,并演练后续分支如何更新。
  • 已进入审查的分支尽量保持稳定;确需 rebase 时通知审查者。

巨型 AI PR 的根本问题不是代理写得太快,而是生成速度超过了团队验证决策的速度。把“生成一个 PR”改成“生成一组有依赖、有测试、可按顺序合并的 PR”,才能让自动化产出真正进入日常工程流程。


相关推荐