本文将分为三个部分:
- 为什么需要提交规范?
- 提交规范详解(核心内容)
- 与 Code Review 流程的结合
1. 为什么需要提交规范?
在 Code Review 前,如果提交的代码杂乱无章,审查者会非常痛苦:
- 理解成本高:审查者需要花费大量时间猜测这个提交到底做了什么和为什么这么做。
- 范围不明确:一个提交里混杂了多个功能的修改,难以聚焦审查。
- 历史追溯困难:混乱的提交信息使得日后排查问题、生成变更日志(Changelog)变得几乎不可能。
良好的提交规范旨在解决这些问题,它的核心目标是:让每一次提交都是一个逻辑独立、意图明确、易于理解的故事单元。
2. 提交规范详解
一份优秀的提交(Commit)主要由两部分组成:
- 提交信息
- 提交内容(代码变更集)
A. 提交信息规范
提交信息是写给未来维护者(包括你自己) 的说明文档。一个常见的规范格式是:
<类型>[可选 范围]: <主题>[空行][正文][空行][脚注]
举例说明:
feat(auth): add login with GitHub OAuth- Add new `GithubOAuthProvider` class implementing the OAuth flow.
- Extend `User` model to include `oauth_provider` and `oauth_id` fields.
- Add unit tests for the new provider.Closes #123
BREAKING CHANGE: The `User.login()` method now returns a Promise.
逐部分解析:
-
类型(Type): 说明本次提交的性质。常用类型包括:
feat
: 新功能。fix
: 修复 bug。docs
: 仅文档更改。style
: 不影响代码逻辑的格式修改(如空格、分号)。refactor
: 既不是新功能也不是 bug 修复的代码重构。perf
: 性能优化。test
: 增加或修改测试用例。chore
: 构建过程或辅助工具的变动(如更新依赖)。
-
范围(Scope,可选): 说明本次提交影响的模块或组件。例如
(auth)
,(user-api)
,(ui-component)
。这让审查者能快速定位受影响的核心区域。 -
主题(Subject): 对本次更改的简短描述。
- 规范:使用祈使句、现在时(如 "add", 而不是 "added" 或 "adds");首字母不需大写;结尾不加句号。
- 长度:建议在50个字符以内。
-
正文(Body,可选): 详细说明做了什么和为什么这么做,而不是怎么做的(代码本身展示了怎么做)。
- 与之前的代码有何不同?
- 为什么这个解决方案是合理的? (尤其是对于复杂的逻辑)
- 是否有其他考虑过的方案?
- 每行长度建议在72个字符以内。
-
脚注(Footer,可选): 用于存放元数据。
- 关闭 Issue:
Closes #123, Fixes #456
。 - 破坏性变更:如果本次提交是不兼容的变更,必须用
BREAKING CHANGE:
开头,并描述变更详情和迁移指南。
- 关闭 Issue:
B. 提交内容规范
比提交信息更重要的是提交的内容本身。核心原则是:原子提交。
-
一个提交只做一件事:
- 正确示例:提交A只实现新功能,提交B只重构相关代码,提交C只修改文档。
- 错误示例:一个提交里既修复了bug,又重构了代码,还顺手格式化了文件。
-
为什么原子提交重要?
- 易于审查:审查者可以轻松理解一个小的、逻辑完整的变更。
- 易于回滚:如果某个功能引入问题,可以安全地回滚单个提交,而不会影响其他修改。
- 易于定位问题:使用
git bisect
等工具时,原子提交能快速定位引入问题的具体变更。
3. 与 Code Review 流程的结合
提交规范是 Code Review 的前置条件。一个理想的流程如下:
场景:为购物车添加商品数量验证功能
步骤 1: 创建功能分支
git checkout -b feature/add-cart-quantity-validation
步骤 2: 进行原子开发与提交
-
提交 1: 添加验证逻辑
# 假设你修改了 shopping_cart.py git add shopping_cart.py git commit -m "feat(cart): add quantity validation for items- Validate that item quantity is a positive integer. - Throw `InvalidQuantityError` if validation fails. - Add relevant unit tests for valid and invalid cases."
-
提交 2: 更新 API 文档
# 假设你更新了 api_docs.md git add api_docs.md git commit -m "docs(api): update cart endpoint docs with quantity rulesDocument the new validation rule for the `quantity` field in the `POST /cart/items` endpoint."
步骤 3: 推送到远程并发起 Pull Request (PR) / Merge Request (MR)
此时,你的 PR 中将包含两个清晰、独立的提交。审查者可以:
- 快速浏览提交历史,了解工作内容。
- 分别审查每个提交,重点关注核心逻辑(第一个提交)和文档(第二个提交)。
- 如果发现文档有问题,可以直接评论在第二个提交上,而不会影响第一个提交的讨论。
步骤 4: 根据审查意见修改
审查者建议在验证逻辑中加入上限检查。
- 不要直接提交,而是使用
git commit --amend
或git rebase -i
来修正上一个相关的提交,保持历史整洁。
# 修改 shopping_cart.py 文件,添加上限检查
git add shopping_cart.py
git commit --amend # 这会将修改合并到 "feat(cart): add quantity validation..." 这个提交中
# 在打开的编辑器中,更新提交信息(如果需要的话):
# feat(cart): add quantity validation for items
#
# - Validate that item quantity is a positive integer between 1-99.
# - Throw `InvalidQuantityError` if validation fails.
# - Add relevant unit tests for valid and invalid cases.
步骤 5: 推送更新
由于修改了历史,需要强制推送(在功能分支上通常是安全的):
git push -f origin feature/add-cart-quantity-validation
PR/MR 会自动更新,审查者看到的是整理后最清晰的提交历史。
总结:优秀提交规范的核心价值
规范要点 | 对 Code Review 的好处 | 反面案例的坏处 |
---|---|---|
清晰的提交信息 | 审查者秒懂提交意图,降低沟通成本。 | fix a bug , 审查者需要猜是什么bug。 |
原子提交 | 审查小而精的代码块,思路不被打断,容易发现深层问题。 | 一个提交修改20个文件,混杂功能、修复、格式,审查如同大海捞针。 |
逻辑独立的变更集 | 可以按提交逐个审查、通过甚至回滚。 | 代码耦合严重,审查一个功能必须理解所有无关改动。 |
工具推荐:
- commitizen: 一个交互式工具,帮助你生成符合规范(如 Angular Convention)的提交信息。
- husky + commitlint: 在 Git 提交时自动检查提交信息格式,确保规范被遵守。
遵循良好的提交规范,不仅是对审查者的尊重,更是对项目未来可维护性的投资,也是每一位专业工程师应具备的基本素养。