Featured image of post 如何正确地书写 Git Commit

如何正确地书写 Git Commit

- 让你的 Git Commit 更加规范

前言

啊 🤔 马上毕业面临找工作 = =,然后上课发呆。突然想起来工作室的一位前辈去腾讯实习期间积累下的一些知识,并传授给了我们。然后就有了这次的博文:如何正确且规范地书写 Git Commit。一直想记在博客里来着。最近一堆没用的破事儿压着我喘不过气。好在这次趁着闲下来,凭借几年前的记忆以及搜集到的知识整理好书写如下。

Git Commit 规范

直接上干货。目前最通用的是 Conventional Commits(约定式提交) 规范,提交信息的第一行以一个类型开头,常用类型如下:

类型含义
feat引入了新功能或功能改进
fix修复 Bug
docs文档的变更,如更新文档或添加注释
style代码风格的变更,如格式调整、空格和缩进的修改,不涉及功能修改
refactor代码重构,既不修复错误也不添加新功能
perf性能优化
test添加或修改测试
build构建系统或外部依赖的变更,如 webpack、npm 依赖
ciCI 配置文件和脚本的变更,如 GitHub Actions
chore其他与构建过程或辅助工具相关的杂项变更,如修改构建脚本、配置文件等
revert回滚之前的某次提交

为什么要写规范的 Git Commit

先说现在存在的痛点。

拿一个我的反面例子来说:

反面例子:含糊的提交信息

文档:为一些代码增加了一些文档。

这还算基本合格,至少你还能通过 commit msg 看出大致干了什么。但是有时候我们会遇到更糟糕的情况。

比如我直接在 GitHub 上在线编辑某个仓库中的某一段代码,顺带直接 commit。默认情况下,GitHub 缺省的 commit message 是 Update xxx(文件名)。

刚开始几天可能觉得没什么。等过了几天你就忘了你 update 了啥。或者堆了一堆 commit,message 通篇都是 Update xxx。

痛点来了!!= =

如果恰好这时候你想让仓库回溯到某个版本,你就会发现前面提到的痛点:你根本不知道你 update 了啥。这时候你就会后悔当初为什么不写一个规范的 commit message 来规避这个问题。

Git Commit 规范的好处

  • 有助于团队协作,提升团队效率。
  • 有助于代码的维护、追踪、回滚、审查、发布、迭代、管理、规范、整洁、可读性、可维护性、可扩展性、可测试性、可靠性、稳定性、安全性、性能、质量、效率、可用性。(让 ChatGPT 帮我想了一些词)

说点实在的:

  • git log --oneline 扫一眼就知道每次提交干了什么;
  • 想找某次修复,git log --grep "^fix" 就能筛出来;
  • 工具可以根据 feat / fix / BREAKING CHANGE 自动生成 CHANGELOG、自动决定版本号。

Git Commit 规范的实践

完整格式

一条完整的提交信息分为三部分:标题(header)、正文(body) 和 脚注(footer),之间用空行隔开:

1
2
3
4
5
<type>(<scope>): <subject>

<body>

<footer>

一条规范提交信息的结构

  • type:上面表格里的类型,必填;
  • scope:影响范围,可选,比如模块名 auth、api、ui;
  • subject:一句话说明做了什么,必填。建议用祈使句、首字母小写、结尾不加句号,标题整行控制在 50 个字符左右;
  • body:可选,说明为什么改、改了什么,每行 72 个字符左右换行;
  • footer:可选,用于关联 Issue(Closes #123)或声明不兼容变更(BREAKING CHANGE: ...)。

几个例子

只有标题的小改动:

1
docs: fix typo in README

带范围和正文:

1
2
3
4
5
6
feat(auth): support login with GitHub OAuth

Users can now sign in with their GitHub account.
The access token is stored in an HttpOnly cookie.

Closes #42

不兼容变更,在类型后加 !,并在脚注中说明:

1
2
3
feat(api)!: remove v1 endpoints

BREAKING CHANGE: /api/v1/* has been removed, use /api/v2/* instead.

写错了怎么办

最近一次提交还没推送的话,直接修改:

1
git commit --amend

要改更早的提交,用交互式变基,把对应行的 pick 改成 reword:

1
git rebase -i HEAD~3

已经推送到公共分支的提交不要随便改写历史,否则会给协作者带来麻烦。

一次提交只做一件事

规范的提交信息的前提是规范的提交:修 Bug 和加功能分开提交,格式化代码单独提交。如果一次改动里混了多件事,可以用 git add -p 按块暂存,分几次提交。

Git Commit 规范的工具

靠自觉总有忘的时候,交给工具来约束更靠谱。下面的工具都基于 Node.js,适用于任何语言的项目(只要装了 Node.js 即可)。

Commitizen:交互式填写

Commitizen 用问答的方式引导你填写 type、scope、subject,不用记格式:

1
2
npm install -g commitizen
commitizen init cz-conventional-changelog --save-dev --save-exact

之后用 git cz 代替 git commit 即可。

commitlint + husky:提交时自动检查

commitlint 负责检查提交信息是否符合规范,husky 负责在 commit-msg 钩子里调用它:

1
2
3
4
5
6
7
8
# 安装 commitlint 和约定式提交的规则集
npm install --save-dev @commitlint/cli @commitlint/config-conventional
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

# 安装 husky 并添加 commit-msg 钩子
npm install --save-dev husky
npx husky init
echo "npx --no -- commitlint --edit \$1" > .husky/commit-msg

配置好以后,不规范的提交会被直接拦下来:

commitlint 拦截不规范的提交

编辑器插件

  • VS Code:Conventional Commits 插件,在源代码管理面板里一步步选择类型和范围;
  • JetBrains 系列 IDE:插件市场搜索 Conventional Commit。

总结

  • 标题用 type(scope): subject,一眼看出改了什么;
  • 正文写清楚为什么改;
  • 一次提交只做一件事;
  • 用 commitlint + husky 兜底,团队里就不会再出现满屏的 Update xxx 了。

参考

由 Hugo 强力驱动