PR 纪律
概述
PR 会消耗团队时间。这里的纪律是预防浪费(因意外范围导致的重新审查、合并到错误分支、归属错误)而不是事后补救。
原则: 涉及架构时需事先达成共识,始终保持格式一致,合并目标需双重确认。
在开始时声明: "正在为此 PR 应用 pr-discipline。"
步骤 1:在编码前与维护者对齐(如适用)
在打开 PR 之前,如果变更涉及以下方面,请向模块维护者发送一段提案:
- 现有端点的响应方式。
- DTO 或验证器的结构。
- 跨仓库模式(验证器、服务、错误处理)。
- 架构抽象(新的装饰器、服务层、模块级别的模式)。
模板:
"[维护者],我将为功能 Y 做 X。范围:a, b, c。其他 X 因 Z 原因保持不变。可以吗?"
等待确认。若有异议,可以通过文本迭代(成本低)。如果同意了,PR 将无需事后讨论。
不适用于: 不改变契约的错误修复、遵循现有模式的功能、模块内部的代码重构、仅文档或仅测试。
步骤 2:验证 PR 的正确目标分支
PR 的目标分支不总是 main。通过调用 use-worktrees 技能来解决(步骤 1 — 完整瀑布流程)。一旦解决,该设置会持久化到自动记忆,未来调用无需再次询问。
此技能尊重的常见工作流:
| 工作流 | 功能分支基于 | PR 指向 |
|---|---|---|
| 带暂存缓冲区的后端 | staging | staging(之后 staging → main 另外处理) |
| 移动端 / 简单 Web | main 或 main-web | main 或 main-web |
| 传统 Gitflow | dev | dev(之后 dev → master) |
| 主干开发 | main 或 trunk | main 或 trunk |
不要假设;始终确定。
步骤 3:在创建之前先复用
在添加任何文件、验证器、守卫、服务、组件、辅助函数、常量或新类型之前:调用 reuse-existing-patterns 技能。该技能涵盖如何按类别搜索、何时使用现有内容以及何时合理创建并行内容(需在 PR 正文中说明理由)。
在形成这种思维习惯之前不要开始编码——这是审查评论中出现类似“这已经存在了,请使用现有模式”的首要原因。
步骤 4:创建 PR — 标题、正文、归属
标题
- 不超过 70 个字符。长的内容放到正文。
- 遵循仓库格式(如果使用 Conventional Commits 则采用;否则使用短句)。
- 使用团队语言(如果团队用中文写,标题也用中文)。
正文
最小模板:
## 摘要
<1-3 个要点说明变更内容和原因>
## 测试计划
- [ ] <要验证的命令或流程>
- [ ] <其他>
## 风险
<边界情况、回滚计划、依赖项>
如果仓库有模板(.github/PULL_REQUEST_TEMPLATE.md),以此为基础。
归属(提交身份)
永远不要在 git commit 中传递 -c user.email=... 或 -c user.name=...。工作仓库已有正确的本地配置;全局配置通常是个人配置。意外覆盖会将工作提交归属于个人 GitHub 帐户。
在推送前验证:
git log -1 --format='%an <%ae>'
如果邮箱不是工作邮箱,不要推送——先修正:
git commit --amend --reset-author # 使用当前本地配置
不要仅仅为了归属而重写 main/staging(受保护分支)的历史——强制推送的成本大于收益。
步骤 5:上传带有干净反引号的 Markdown
gh pr edit --body-file 和 gh pr comment --body 会转义反引号为 ```,破坏格式。解决方案:使用 JSON 负载的 gh api -X PATCH。
python3 <<'PY'
import json, subprocess
with open('/tmp/body.md') as f:
body = f.read()
subprocess.run(
['gh', 'api', '-X', 'PATCH', 'repos/<org>/<repo>/pulls/<num>', '--input', '-'],
input=json.dumps({'body': body}), text=True, check=True
)
PY
验证:
gh pr view <num> --json body --jq .body | head -10
如果反引号显示为字面量(未转义),则正确。
步骤 6:审查评论风格
- 按严重程度分组:阻塞性 / 次要改进 / 小瑕疵。
- 每个发现一个要点,一行以内:是什么 + 为什么 + 建议修复。
- 使用
file.ts:42格式引用行号(在 GitHub 上可点击)。 - 先说明理由,再给出观察。就像在对等评审的边注,而不是外部审计。
- 如果作者在 PR 正文中记录了推理,与该推理互动——不要从头开始重新发明。
- 不要使用诸如 "B1"、"M2" 之类的人工标签。在没有帮助的情况下,不要使用代码块示例。
经验丰富的审查者会注意到的“AI 机械感”:结构过于对称、相同的过渡短语、缺乏作者上下文的要点。
步骤 7:合并 — 根据团队工作流选择压缩或合并
验证仓库的约定。常见模式:
| 仓库类型 | feature → integration | integration → main |
|---|---|---|
| 带暂存的后端 | 压缩 | 合并提交 |
| 无暂存的移动端/Web | 压缩 或合并 | 不适用 |
| 传统 Gitflow | 合并到 dev | 合并到 master |
为什么在带暂存的仓库中存在不对称: 如果对 staging → main 进行压缩,PR 看起来会很大(重复 N 个已压缩的功能)。合并提交可以保持功能列表原样,就像它们进入 staging 时一样。
# feature → staging
gh pr merge --squash <num>
# staging → main (对于分离的仓库)
gh pr merge --merge <num>
如果仓库有 staging,永远不要直接合并到 main:
git revert会撤销代码,但提交会永远留在历史中——对所有人可见。- 在点击之前三倍检查
gh pr create的--base和 GitHub UI 中的合并目标。 - 如果存在疑问,在执行
gh pr merge之前询问用户 "是否需要合并到 staging?"
快速参考
| 情景 | 操作 |
|---|---|
| 变更涉及契约或架构 | 步骤 1:与维护者对齐 |
| 创建分支 | 步骤 2:使用瀑布流程确定目标 |
| 开始实现 | 步骤 3:检查仓库中是否已存在该模式 |
| 准备打开 PR | 步骤 4:标题 <70 字符,正文使用模板,验证归属 |
| 包含代码的正文或评论 | 步骤 5:使用 gh api PATCH 配合 JSON |
| 留下审查评论 | 步骤 6:按严重程度分类要点,先说明理由 |
| 合并 | 步骤 7:根据约定选择压缩或合并 |
| 仓库带暂存 | 永远不要直接合并到 main |
常见错误
- 未预先对齐就打开架构性 PR。 会导致 2-3 轮重新审查和事后讨论。在编码前发送提案段落。
- 在已有等价物的情况下创建新文件或抽象。 先搜索(步骤 3)。审查者会指出来。
- 标题超过 70 个字符并包含完整描述。 标题要短,详情放到正文。
- 在脚本化提交中使用
-c user.email。 会用个人全局配置覆盖本地工作配置。 - 使用
gh pr edit --body-file file.md处理包含反引号的内容。 它会转义反引号。请使用gh api PATCH配合 JSON。 - 使用叙述性散文进行审查。 用户希望按严重程度分类的要点——可扫描,而非叙述。
- 对 staging → main 进行压缩。 会重复每个功能已经压缩过的历史。请使用合并提交。
- “因为变更很小”而直接合并到 main。 提交会永远留在历史中,对所有人可见。
危险信号
永远不要:
- 打开涉及契约/架构的 PR 而不事先对齐。
- 在已有等价物的情况下创建并行文件或抽象。
- 在
git commit中传递-c user.email/-c user.name。 - 在未验证
git log -1 --format='%ae'的情况下推送。 - 对包含反引号的 Markdown 使用
gh pr edit --body-file。 - 在带暂存的仓库中直接合并到 main。
- 压缩 staging → main。
- 不按严重程度分组而留下审查评论。
始终:
- 架构变更前与维护者对齐。
- 使用瀑布流程确定 PR 的目标分支,而不是假设
main。 - 在创建新模式之前检查仓库中是否已存在该模式。
- 标题 <70 字符 + 正文包含摘要、测试计划、风险。
- 在推送前验证提交归属。
- 使用
gh api PATCH配合 JSON 处理包含代码的 Markdown。 - 审查评论按严重程度分类要点,先说明理由。
- 在 feature → integration 时压缩,在 integration → main 时使用合并提交。