Skip to main content

[Cli] Git提交规范之消息提交

标准化大厂编程规范解决方案之 ESLint + Git Hooks(3)

在前面我们通过 prettier + ESLint 解决了代码格式的问题,但是我们之前也说过 编程规范 指的可不仅仅只是 代码格式规范 。 除了 代码格式规范 之外,还有另外一个很重要的规范就是 git 提交规范!

在现在的项目开发中,通常情况下,我们都会通过 git 来管理项目。只要通过 git 来管理项目,那么就必然会遇到使用 git 提交代码的场景

当我们执行 git commit -m "描述信息" 的时候,我们知道此时必须添加一个描述信息。 而很多人的描述 “天马行空” ,这样就会导致别人在看你的提交记录时,看不懂你说的什么意思?不知道你当前的这次提交到底做了什么事情?会不会存在潜在的风险? 所以 git 提交规范 势在必行。

对于 git 提交规范 来说,不同的团队可能会有不同的标准,目前使用较多的 Angular 团队规范 延伸出的 Conventional Commits specification(约定式提交) 为例,详解 git 提交规范

约定式提交

约定式提交规范要求如下:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

-------- 翻译 -------------

<类型>[可选 范围]: <描述>

[可选 正文]

[可选 脚注]

其中 <type> 类型,必须是一个可选的值,比如:

  1. 新功能:feat
  2. 修复:fix
  3. 文档变更:docs
  4. ....

也就是说,如果要按照 约定式提交规范 来去做的化,那么你的一次提交描述应该式这个样子的: commit

要是每次都这么写,写到猴年马月了!

所以需要使用 Commitizen 助你规范化提交代码

Commitizen

通过上面我们了解到如果严格按照约定式提交规范, 来手动进行代码提交的话,那么是一件非常痛苦的事情,但是 git 提交规范的处理 又势在必行,那么怎么办呢? 经过很多人的冥思苦想, 出现了一种叫做 git 提交规范化工具 的东西,而 commitizen 就是其中的佼佼者! commitizen 仓库名为 cz-cli ,它提供了一个 git cz 的指令用于代替 git commit,简单一句话介绍它:

当你使用 commitizen 进行代码提交(git commit)时,commitizen 会提交你在提交时填写所有必需的提交字段!

这句话怎么解释呢?不用着急,下面就来安装并且使用一下 commitizen ,使用完成之后自然就明白了这句话的意思!

  1. 全局安装Commitizen

    npm install -g commitizen@4.2.4
  2. 安装并配置 cz-customizable 插件

    1. 使用 npm 下载 cz-customizable

      npm i cz-customizable@6.3.0 --save-dev
    2. 添加以下配置到 package.json

      ...
      "config": {
      "commitizen": {
      "path": "node_modules/cz-customizable"
      }
      }
  3. 项目根目录下创建 .cz-config.js 自定义提示文件

    module.exports = {
    // 可选类型
    types: [
    { value: "feat", name: "feat: 新功能" },
    { value: "fix", name: "fix: 修复" },
    { value: "docs", name: "docs: 文档变更" },
    { value: "style", name: "style: 代码格式(不影响代码运行的变动)" },
    {
    value: "refactor",
    name: "refactor: 重构(既不是增加feature,也不是修复bug)",
    },
    { value: "perf", name: "perf: 性能优化" },
    { value: "test", name: "test: 增加测试" },
    { value: "chore", name: "chore: 构建过程或辅助工具的变动" },
    { value: "revert", name: "revert: 回退" },
    { value: "build", name: "build: 打包" },
    ],
    // 消息步骤
    messages: {
    type: "请选择提交类型:",
    customScope: "请输入修改范围(可选):",
    subject: "请简要描述提交(必填):",
    body: "请输入详细描述(可选):",
    footer: "请输入要关闭的issue(可选):",
    confirmCommit: "确认使用以上信息提交?(y/n/e/h)",
    },
    // 选择跳过的问题
    skipQuestions: ["body", "footer"],
    // subject文字长度默认是72
    subjectLimit: 72,
    };
  4. 使用 git cz 代替 git commit 使用 git cz 代替 git commit,即可看到提示内容

那么到这里就可以使用git cz 来代替了 git commit 实现了规范化的提交诉求了,但是当前依然存在着一个问题,那就是必须要通过 git cz 指令才可以完成规范化提交!

那么如果有马虎的同事,忘记了使用 git cz 指令,直接就提交了怎么办呢?

那么有没有方式来限制这种错误的出现呢?答案是有的!

所以需要 Git Hooks

Git Hooks

上面我们使用了 git cz 来代替了 git commit 实现了规范化的提交诉求,但是依然存在着有人会忘记使用的问题。
那么我们应该如何去进行解决。

先来明确一下我们最终要实现的效果:

我们希望:

当《提交描述信息》不符合 约定式提交规范 的时候,阻止当前的提交,并抛出对应的错误提示

而要实现这个目的,就需要先来了解一个概念,叫做 Git hooks(git 钩子 || git 回调方法) 也就是:git 在执行某个事件之前或之后进行一些其他额外的操作

而我们所期望的 阻止不合规的提交消息,那么就需要使用到 hooks 的钩子函数。

下面是我整理出来的所有的 hooks ,其中加粗的是常用到的 hooks

Git Hook调用时机说明
pre-applypatchgit am执行前
applypatch-msggit am执行前
post-applypatchgit am执行后不影响git am的结果
pre-commitgit commit执行前可以用git commit --no-verify绕过
commit-msggit commit执行前可以用git commit --no-verify绕过
post-commitgit commit执行后不影响git commit的结果
pre-merge-commitgit merge执行前可以用git merge --no-verify绕过。
prepare-commit-msggit commit执行后,编辑器打开之前
pre-rebasegit rebase执行前
post-checkoutgit checkoutgit switch执行后如果不使用--no-checkout参数,则在git clone之后也会执行。
post-mergegit commit执行后在执行git pull时也会被调用
pre-pushgit push执行前
pre-receivegit-receive-pack执行前
update
post-receivegit-receive-pack执行后不影响git-receive-pack的结果
post-updategit-receive-packgit push 作出反应并更新仓库中的引用时
push-to-checkout当`git-receive-packgit push做出反应并更新仓库中的引用时,以及当推送试图更新当前被签出的分支且receive.denyCurrentBranch配置被设置为updateInstead
pre-auto-gcgit gc --auto执行前
post-rewrite执行git commit --amendgit rebase
sendemail-validategit send-email执行前
fsmonitor-watchman配置core.fsmonitor被设置为.git/hooks/fsmonitor-watchman.git/hooks/fsmonitor-watchmanv2
p4-pre-submitgit-p4 submit执行前可以用git-p4 submit --no-verify绕过
p4-prepare-changelistgit-p4 submit执行后,编辑器启动前可以用git-p4 submit --no-verify绕过
p4-changelistgit-p4 submit执行并编辑完changelist message可以用git-p4 submit --no-verify绕过
p4-post-changelistgit-p4 submit执行后
post-index-change索引被写入到read-cache.c do_write_locked_index
tip

详细的 HOOKS介绍 可点击这里查看

整体的 hooks 非常多,其中用的比较多的其实只有两个:

Git Hook调用时机说明
pre-commitgit commit执行前
它不接受任何参数,并且在获取提交日志消息并进行提交之前被调用。脚本git commit以非零状态退出会导致命令在创建提交之前中止。
可以用git commit --no-verify绕过
commit-msggit commit执行前
可用于将消息规范化为某种项目标准格式。
还可用于在检查消息文件后拒绝提交。
可以用git commit --no-verify绕过

简单来说这两个钩子:

  1. commit-msg:可以用来规范化标准格式,并且可以按需指定是否要拒绝本次提交
  2. pre-commit:会在提交前被调用,并且可以按需指定是否要拒绝本次提交

而接下来要做的关键,就在这两个钩子上面。

使用 husky + commitlint 检查提交描述是否符合规范要求

了解了 git hooks 的概念,那么接下来就使用 git hooks 来去校验提交信息。

要完成这么个目标,需要使用两个工具:

  1. commitlint:用于检查提交信息

  2. husky:是git hooks工具

两个包的说明
  1. commitlint 它可以检查提交信息, 但是只能起到检查的效果, 那么在何时进行检查就需要用到第二个库
  2. husky 来指定当前的 commit lint, 在 git hook 的 commit-msg 的 hooks 下执行, 来达到执行 git commit 的时候通过第一个库 commitlint 来进行提交信息校验的功能

注意:npm 需要在 7.x 以上版本!!!!!

那么下面分别安装一下这两个工具:

commitlint

  1. 安装依赖:

npm install --save-dev @commitlint/config-conventional@12.1.4 @commitlint/cli@12.1.4

  1. 创建 commitlint.config.js 文件

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

// 这句命令对外导出一个对象, 这个对象继承了这个包

  1. 打开 commitlint.config.js , 增加配置项( config-conventional 默认配置点击可查看 ):
module.exports = {
// 继承的规则
extends: ["@commitlint/config-conventional"],
// 定义规则类型
rules: {
// type 类型定义,表示 git 提交的 type 必须在以下类型范围内
"type-enum": [
// 当前验证的错误级别, 2表示错误级别
2,
// 在什么情况下进行验证
"always",
// 泛型内容, 这里应该在之前定义的cz types里一样
[
"feat", // 新功能 feature
"fix", // 修复 bug
"docs", // 文档注释
"style", // 代码格式(不影响代码运行的变动)
"refactor", // 重构(既不增加新功能,也不是修复bug)
"perf", // 性能优化
"test", // 增加测试
"chore", // 构建过程或辅助工具的变动
"revert", // 回退
"build", // 打包
],
],
// subject 大小写不做校验
"subject-case": [0],
},
};

注意:确保保存为 UTF-8 的编码格式,否则可能会出现以下错误:

image-20210710121456416

那么如何确定当前保存文件编码格式是UTF-8?

在 VSCODE 右下角 utf

此时, commitlint 已经安装并且配置完成了, 但是如果希望使用 commitlint 加入到 git hooks 里面, 还需要使用到另外一个库husky

husky

它是一个可以用来检测 git hooks 工具的东西

  1. 安装依赖:

    npm install husky@7.0.1 --save-dev
  2. 启动 hooks , 生成 .husky 文件夹

    npx husky install

    husky

  3. package.json 中生成 prepare 指令( 需要 npm > 7.0 版本

    npm set-script prepare "husky install"

    prepare

  4. 执行 prepare 指令

    npm run prepare
  5. 执行成功,提示 husky - Git hooks installed

  6. 执行以下指令, 指令的作用是添加 commitlinthookhusky中,也就是通过husky来监听git hookscommit-msg的回调里去执行 commit linint 来完成提交代码的检测. 并指令在 commit-msghooks 下执行 npx --no-install commitlint --edit "$1" 指令

    npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
  7. 此时的 .husky 的文件结构 多出的 commit-msg 这个文件会在 commit-msg 的 git hook 里执行, 执行的时候会去执行这个文件里的 npx --no-install commitlint --edit "$1"这句指令

  8. commit-msg 的文件内容 commit-msg

至此, 不符合规范的 commit 将不再可提交:

PS F:\xxxxxxxxxxxxxxxxxxxxx\目录> git commit -m "测试"
⧗ input: 测试
✖ subject may not be empty [subject-empty]
✖ type may not be empty [type-empty]

✖ found 2 problems, 0 warnings
ⓘ Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint

husky - commit-msg hook exited with code 1 (error)

那么至此,就已经处理好了 强制规范化的提交要求,到现在 不符合规范的提交信息,将不可在被提交!

那么到这里 规范化目标 就完成了吗?

当然没有!

现在还缺少一个 规范化的处理 ,那就是 代码格式提交规范处理!

也就是说目前位置做的都是git 的消息提交规范, 但是我们的代码格式提交规范还没有做

所以需要下一步通过 pre-commit 处理提交时代码规范