返回首页

Git / 工作流 / 代码规范

如何规范提交代码 —— 优雅的 Git Commit Message 写法

本文描述了 Git commit 规范和 commit message 的 Angular 标准写法,并推荐了一个规范代码的工具。

左侧涂乱墨迹的碎纸堆经过一根蓝色横线,变成右侧整齐排列的彩色标签卡片

为什么要规范 Git commit

令人不适的提交和 commit message

看看这几种糟糕的提交,你一定在项目里遇到过:

  1. 偷懒写法:git commit -m 'small change'
  2. 预先承诺式写法:git commit -m 'something which hasn't been done'
  3. 啰哩巴嗦:git commit -m 'null check added' —— 连续 3–4 个这样的 commit(其实可以 squash 成一次有意义的提交)
  4. 憋大招式:git commit -m 'something done1, something done2, something done3, something done4'
  5. 迷雾重重:git commit -m 'merge message'

从上述糟糕示范可以发现,不好的 Git 提交存在以下问题:

  1. 信息不足:让我们在检查提交历史或版本回退时,很难知道这次提交发生了什么变动。
  2. 提交未完成的功能:如果回退,带来的影响可太大了,应该特别注意 ⚠️
  3. 拆分不合理:一个功能分成了多次提交。例如空值检查这一个 feature 提交了多次,但只有最后一次才是有用的。Git commit 不能当作你保存草稿的工具。
  4. 一次 commit 中实现多个改动:除非是 Initial commit,否则一次 commit 中最好只有一次逻辑上的改动。否则之后回退时会带来较大的影响。
  5. 本地 merge 不写来源:在本地 merge 代码,也不说 merge 的原因、来源,然后就 commit 后推到远程,甚至合并到了 main 分支。本质上还是没写清 commit message,但影响非常大,所以单独列出。

良好的 Git 提交规范

良好的提交通常具有四个属性 —— ACID:

  • A 原子性:提交应代表一个逻辑改变
  • C 一致性:每个提交都应保持代码处于一致的状态
  • I 增量式:提交顺序应该是有解释性的;应该记录参与编写代码的思考过程
  • D 文档化:改变的意义(以及背后的推理)应该在你的提交信息中传达

遵循规范带来的好处:

  1. 可读性好——根据 commit 信息就能明确知道本次提交的修改内容及影响范围
  2. 可以根据不同的提交类型,过滤掉不想关注的提交,提高效率
  3. 可以自动化生成 changelog,甚至可以自动更新语义化的版本号
  4. 可以降低 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 指本次代码影响的范围。范围较大时可以用 * 代替。一般可以是 UtilServiceController 等。

Subject

对变更的简洁描述:

  • 使用祈使句、现在时态:change 而不是 changedchanges
  • 第一个字母不要大写
  • 末尾没有句点

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

有两个注意点:

  1. 使用第一人称现在时,比如 change 而不是 changedchanges
  2. 应该说明代码变动的动机,以及与以前行为的对比

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 做提交前校验,新人也能一次上手。

参考文章