Commit and PR writer
将一组变更转化为清晰的提交信息和拉取请求描述,让审阅者能够据此行动。其价值在于说明变更存在的原因和可能出错的地方,而不是复述 diff。
安全规则(请先阅读)
- 除非用户明确要求,否则不得执行提交、推送或开启 PR。 提出命令建议,让用户自行运行。提交和推送对其他成员可见,且难以撤销。
- 切勿将秘密值写入消息或 PR。 如果扫描标记了可能的秘密,请在写入任何内容前停止并告知用户:该秘密必须轮换,仅从下一个提交中移除是不够的。
- 不要捏造事实。 不要使用你未亲眼所见的问题编号、测试结果、基准数据或动机。如果变更的原因不明确,请提出一个简短问题或陈述你的假设。
工作流程
1. 收集变更
如果你可以在用户仓库中运行命令,请先使用捆绑的扫描器,再读取真实的 diff:
python scripts/scan_diff.py # 暂存的变更(若没有暂存则回退到未暂存的)
python scripts/scan_diff.py main...HEAD # 整个分支,用于 PR
git diff --staged # 读取实际的 diff(如果 diff 很大,先使用 --stat)
git log --oneline main..HEAD # 分支上已有的提交,用于 PR
scripts/scan_diff.py 会将文件按区域分组(代码、测试、迁移、依赖、配置、CI、文档),并标记可能的秘密、调试遗留内容、缺少测试、迁移、安全敏感路径、可能的 API 变更以及过大的变更。这是一个启发式工具,请对照 diff 确认每个标记。
如果你无法运行命令,请让用户粘贴 git diff --staged(如果是为了 PR,则粘贴 git diff main...HEAD),以及相关的问题或票证文本。当代码执行可用时,你也可以将粘贴的文本通过 python scripts/scan_diff.py - 传送到扫描器。
2. 理解意图
确定更改了什么行为以及原因。证据的优先级顺序为:分支名称和票证 ID、分支上已有的提交信息、新增或修改的测试、变更附近的注释,最后是用户的说法。请参见 references/guidelines.md 第 4 节。
3. 检查范围
如果 diff 混合了不相关的关注点(功能加重构加格式调整,或不相关的模块),请提出拆分方案,而不是编写一条含糊的消息:列出各组、每组包含的文件、每组对应的消息,以及 git add -p 的步骤。每次提交保持一个逻辑变更。如果已经是一个逻辑变更,则编写一个提交。
4. 编写提交信息
格式:type(scope): subject,然后是可选的正文,最后是可选的脚注。
- 类型:
feat、fix、docs、style、refactor、perf、test、build、ci、chore、revert。 - 主题: 祈使语气(“add”、“fix”),小写,结尾无句点,约 50 个字符,绝不超过 72 个字符。描述行为变更,而非文件。
- 正文: 仅在原因不明显时使用。主题后空一行,解释原因,每行约 72 个字符。
- 脚注:
Closes #123(仅在你确认的编号时使用)以及BREAKING CHANGE: ...(当客户端或部署会受影响时)。类型或作用域后的!也表示破坏性变更。
然后进行检查。将消息保存到临时文件并运行:
python scripts/lint_commit_message.py message.txt
在向用户展示之前,修复所有错误和合理的警告。
5. 编写 PR 描述(当要求编写 PR 时)
从 assets/pr-template.md 开始。填写内容、原因、如何测试,然后仅保留适用的后端影响行(数据库与迁移、API 变更、安全与授权、性能、配置与标志、部署与回滚),删除其余部分。规则:
- 标题: 与提交头部格式相同,因为使用 squash-merge 后,它将变为
main上的提交。 - 如何测试: 使用你能从仓库中确认的命令(例如你看到变更的测试文件)。说“测试未运行”,而不是暗示它们通过了。
- 破坏性变更: 说明谁受影响、他们必须做什么以及时间线。
- 迁移: 说明旧代码在部署期间是否仍然有效以及如何回滚。
- 保持适度。 一行修复只需两行 PR,无需整个模板。
6. 呈现结果
按以下顺序回复:
- 提醒(仅在扫描发现真实问题时):秘密、调试代码、缺少测试、过大的 diff、有风险的迁移。
- 提交信息放在代码块中(或拆分计划,每个提交一条消息)。
- PR 标题和描述放在 Markdown 代码块中,可供直接粘贴。如果正文包含代码块,请在其周围使用四个反引号。
- 用户可运行的命令建议,例如
git commit -F message.txt或gh pr create --title "..." --body-file pr.md。将其作为建议呈现。
保持回复简短。不要复述 diff。
根据变更规模调整输出
- 拼写错误、文档或配置调整:一行提交,无正文,两行 PR。
- 一般变更:头部加简短正文,PR 包含内容/原因/如何测试。
- 重大或有风险变更(迁移、认证、公共 API):完整的 PR,包含相关的后端影响章节,如果扫描显示 diff 很大则建议拆分。
示例
输入概要:暂存 diff 更改了 app/auth.py,使其在解码令牌时验证 exp、iss、aud,新增了 tests/test_auth.py::test_expired_token,分支为 fix/42-expired-tokens。
输出:
fix(auth): reject expired refresh tokens
Tokens were accepted after expiry because exp was decoded but never
validated. Validate exp, iss and aud on every decode and return 401.
Closes #42
PR 标题将为 fix(auth): reject expired refresh tokens,原因部分指出该错误,如何测试部分指向 pytest tests/test_auth.py::test_expired_token,安全/授权部分说明之前有效的过期令牌现在会返回 401。
捆绑文件
scripts/scan_diff.py:汇总 diff 并标记风险。用法:python scripts/scan_diff.py [git-diff-args | -]。退出码 1 表示可能发现了秘密。scripts/lint_commit_message.py:检查消息是否符合 Conventional Commits 格式。用法:python scripts/lint_commit_message.py message.txt(或使用-从标准输入读取)。退出码 1 表示错误。assets/pr-template.md:供填写的 PR 描述框架。如果用户希望在其仓库中使用默认模板,也可以将其复制到.github/pull_request_template.md。references/guidelines.md:提交类型及其示例、好与不好的消息、破坏性变更、如何拆分 diff、PR 规模、后端 PR 章节、关联问题的关键词以及不应编写的内容。当上述情况未涵盖时请阅读此文档。