为什么要规范 Git commit
令人不适的提交和 commit message
看看这几种糟糕的提交,你一定在项目里遇到过:
- 偷懒写法:
git commit -m 'small change' - 预先承诺式写法:
git commit -m 'something which hasn't been done' - 啰哩巴嗦:
git commit -m 'null check added'—— 连续 3–4 个这样的 commit(其实可以 squash 成一次有意义的提交) - 憋大招式:
git commit -m 'something done1, something done2, something done3, something done4' - 迷雾重重:
git commit -m 'merge message'
从上述糟糕示范可以发现,不好的 Git 提交存在以下问题:
- 信息不足:让我们在检查提交历史或版本回退时,很难知道这次提交发生了什么变动。
- 提交未完成的功能:如果回退,带来的影响可太大了,应该特别注意 ⚠️
- 拆分不合理:一个功能分成了多次提交。例如空值检查这一个 feature 提交了多次,但只有最后一次才是有用的。Git commit 不能当作你保存草稿的工具。
- 一次 commit 中实现多个改动:除非是 Initial commit,否则一次 commit 中最好只有一次逻辑上的改动。否则之后回退时会带来较大的影响。
- 本地 merge 不写来源:在本地 merge 代码,也不说 merge 的原因、来源,然后就 commit 后推到远程,甚至合并到了 main 分支。本质上还是没写清 commit message,但影响非常大,所以单独列出。
良好的 Git 提交规范
良好的提交通常具有四个属性 —— ACID:
- A 原子性:提交应代表一个逻辑改变
- C 一致性:每个提交都应保持代码处于一致的状态
- I 增量式:提交顺序应该是有解释性的;应该记录参与编写代码的思考过程
- D 文档化:改变的意义(以及背后的推理)应该在你的提交信息中传达
遵循规范带来的好处:
- 可读性好——根据 commit 信息就能明确知道本次提交的修改内容及影响范围
- 可以根据不同的提交类型,过滤掉不想关注的提交,提高效率
- 可以自动化生成 changelog,甚至可以自动更新语义化的版本号
- 可以降低 code review 的沟通成本
Git Commit Message 规范(Angular 规范)
由标题、正文和页脚三个部分组成,每个部分中间通过空行分隔。
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
标题
标题包括类型、范围和主题三部分。
Type 与 Scope
type 是本次提交的行为类型,固定的几种:
| Type | 说明 |
|---|---|
feat | 增加一个新功能 |
fix | 修复 bug |
docs | 只修改了文档 |
style | 不涉及功能,只是代码的格式、换行等 |
refactor | 代码重构(既不是修复 bug,也不是新功能) |
perf | 改进性能的代码 |
test | 增加测试或更新已有的测试 |
chore | 构建或辅助工具或依赖库的更新 |
hotfix | 紧急修改 |
revert | 版本回滚 |
scope 指本次代码影响的范围。范围较大时可以用 * 代替。一般可以是 Util、Service、Controller 等。
Subject
对变更的简洁描述:
- 使用祈使句、现在时态:
change而不是changed或changes - 第一个字母不要大写
- 末尾没有句点
body 正文
使用祈使句。body 应该包括为什么修改、具体修改了哪些东西。可以分成多行:
More detailed explanatory text, if necessary. Wrap it to
about 72 characters or so.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Use a hanging indent
有两个注意点:
- 使用第一人称现在时,比如
change而不是changed或changes - 应该说明代码变动的动机,以及与以前行为的对比
footer 页脚注释
Footer 部分只用于两种情况。
(1)不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以 BREAKING CHANGE 开头,后面是对变动的描述、以及变动理由和迁移方法:
BREAKING CHANGE: isolate scope bindings definition has changed.
To migrate the code follow the example below:
Before:
scope: {
myAttr: 'attribute',
}
After:
scope: {
myAttr: '@',
}
The removed `inject` wasn't generally useful for directives
so there should be no code using it.
(2)关闭 Issue
如果当前 commit 针对某个 issue,那么可以在 Footer 部分关闭这个 issue:
Closes #234
也可以一次关闭多个:
Closes #123, #245, #992
代码规范工具
推荐使用 Commitizen,它提供了交互式的 commit 生成:输入类型、范围、subject,自动格式化成规范的 commit message。搭配 commitlint 做提交前校验,新人也能一次上手。
