git commit规范化工具

2,675 阅读7分钟

githooks 是什么

Git Hooks 是 git 在执行特定的重要动作发生时触发自定义脚本。包括客户端和服务端钩子。Git Hooks

客户端hooks

客户端钩子由诸如提交和合并这样的操作所调用。包括提交工作流钩子、电子邮件工作流钩子和其它钩子。日常工作中用到的主要是提交工作流钩子,包括 pre-commit prepare-commit-msg commit-msg post-commit

hooks触发时机功能说明
pre-commitgit commit执行前钩子在键入提交信息前运行,用于检查即将提交的快照,该钩子以非零值退出,Git 将放弃此次提交。例如可以利用该钩子检测代码风格是否一致
prepare-commit-msggit merge执行前在启动提交信息编辑器之前,默认信息被创建之后运行。该钩子接收一些选项:存有当前提交信息的文件的路径、提交类型和修补提交的提交的 SHA-1 校验。可以结合模板来使用,动态插入信息
commit-msggit commit 执行前钩子接收一个参数,存有当前提交信息的临时文件的路径。该钩子以非零值退出,Git 将放弃此次提交。可以用来核对提交信息是否遵循指定的模板
post-commitgit commit执行后它不接收任何参数。该钩子一般用于通知之类的事情

绕过githooks

执行 git commit --no-verify 可以绕过 pre-commit 钩子的检察环节。

规范化工具

  • husky githooks 工具
  • lint-staged 格式化已被修改的文件工具,对于已经
  • eslint 检查语法问题插件
  • stylelint 检查css语法插件
  • prettier 自动设置代码格式的工具
  • commitlint 代码提交检测工具
  • commitizen 代码提交内容规范化工具
  • angular规范 使用最广的Commit message规范

🐶 husky

husky是一个npm包,可以让我们很容易的接入 githooks ,控制在git的某个阶段执行脚本。通过在 package.json 文件中包含对象 "husky": {} 来指定执行的脚本。

❗️ 以下版本为 husky@7.0.2

安装方式

自动安装(推荐)

# npm 
npx husky-init && npm install

# Yarn
npx husky-init && yarn

💡 husky-init 是一个一次性命令,用于使用 husky 快速初始化项目,执行完后自动创建 commit-msg 钩子

手动安装

  1. 安装 husky
npm install husky --save-dev
  1. 启用 githooks
npx husky install
  1. 要在安装后自动启用钩子,需要编辑 package.json
npm set-script commit-msg "npx --no-install commitlint --edit "$1""

💡 npm set-script 需要 npm7.x 以上。

👆 至此 👇,效果为

  1. 第二步:.git 目录下多了 .husky 文件夹,且有 commit-msg 钩子
  2. 第三步:package.json 文件中会增加以下代码
// package.json 
{
    "scripts": { 
        "commit-msg": "npx --no-install commitlint --edit "$1"" 
    } 
}
  1. 查看 git 配置项 git config --get core.hooksPath.husky

创建/编辑 hook

在此之前要执行 npx husky install

执行 husky add <file> [cmd] 增加一个钩子。

npx husky add .husky/pre-commit "npm test"

编辑生成的钩子文件 .git/.husky/commit-msg

卸载 husky

卸载husky并删除.husky文件,重置core.hooksPath配置项,并删除 .husky 文件夹

# npm 
npm uninstall husky && git config --unset core.hooksPath && rm -rf .husky
# yarn
yarn remove husky && git config --unset core.hooksPath && rm -rf .husky

尝试提交代码

git commit -m 'test husky pre-commit'
>> husky > pre-commit (node v10.15.3)

💡 若 git commit 未执行husky的脚本,可以尝试重新安装低版本的husky

# npm
npm unstall husky -D
npm install -D husky@4.3.8
# yarn
yarn remove husky
yarn add husky@4.3.8 -D

🚫💩lint-staged

Run linters against staged git files and don't let 💩 slip into your code base!

安装配置

# npm
npm install lint-staged --save-dev
# yarn
yarn add lint-staged -D
// package.json
"husky": {
    "hooks": {
        "pre-commit": "lint-staged"
    }
},
"lint-staged": {
    "*.{js,jsx,ts,tsx}": "eslint",
    "*.{css,less,scss,styl}": "stylelint"
},

尝试提交代码

git commit -m 'test lint-staged'
husky > pre-commit (node v14.17.4)
✔ Preparing...
⚠ Running tasks...
  ❯ Running tasks for *.{js,jsx,ts,tsx,vue}
    ✖ eslint [FAILED]
  ↓ No staged files match *.{css,less,scss,styl} [SKIPPED]
↓ Skipped because of errors from tasks. [SKIPPED]
✔ Reverting to original state because of errors...
✔ Cleaning up...

✖ eslint:

/……/config.ts
  10:1  error  Too many blank lines at the end of file. Max of 0 allowed  no-multiple-empty-lines
  11:1  error  Trailing spaces not allowed                                no-trailing-spaces
  11:5  error  Newline required at end of file but not found              eol-last3 problems (3 errors, 0 warnings)
  3 errors and 0 warnings potentially fixable with the `--fix` option.

commitlint

commitlint 是一个校验提交信息的工具,可以结合 husky 实现对 commit-msg 的检测。

安装

# npm
npm install @commitlint/cli @commitlint/config-conventional -D
# yarn 
yarn add @commitlint/cli @commitlint/config-conventional -D

添加 hook

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'

测试提交

git commit -m '测试'
⧗   input: 测试
✖   subject may not be empty [subject-empty]

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

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

prompt-cli格式化commit-msg

安装

npm install --save-dev @commitlint/prompt-cli

设置scripts

{ "scripts": { "commit": "commit" } }

测试提交

git add .
npm run commit
Please enter a type: [optional] [tab-completion] [header]
<type> holds information about the goal of a change.



<type>(<scope>): <subject>
<body>
<footer>


108 characters left

commitizen

安装

# npm
npm install commitizen cz-conventional-changelog -D
# yarm
yarn add commitizen cz-conventional-changelog -D

配置 commit-msg 选项

// package.json

  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog",
      "types": {
        "🚀 feat": {
          "description": "引入新功能",
          "title": "Features"
        },
        "🐛 fix": {
          "description": "修复bug",
          "title": "Bug Fixes"
        },
        "📝 docs": {
          "description": "撰写文档",
          "title": "Documentation"
        },
        "💄 style": {
          "description": "样式修改",
          "title": "Styles"
        },
        "💬 text": {
          "description": "文案修改",
          "title": "Texts"
        },
        "💩 poo": {
          "description": "重写屎一样的代码",
          "title": "Code Poop"
        },
        "⚡️ perf": {
          "description": "性能优化",
          "title": "Performance Improvements"
        },
        "✅ test": {
          "description": "增加测试",
          "title": "Tests"
        },
        "🏗 build": {
          "description": "影响构建系统或外部依赖项的更改",
          "title": "Builds"
        },
        "✂️ tool": {
          "description": "增加开发快乐值的工具",
          "title": "Tools"
        },
        "💚 ci": {
          "description": "对CI配置文件和脚本的更改(示例范围:Travis, Circle, BrowserStack, SauceLabs)",
          "title": "Continuous Integrations"
        },
        "🧹 chore": {
          "description": "日常杂事",
          "title": "Chores"
        },
        "⏪ revert": {
          "description": "回退历史版本",
          "title": "Reverts"
        },
        "👥 conflict": {
          "description": "修改冲突",
          "title": "Conflict"
        },
        "🚮 delete": {
          "description": "删除文件",
          "title": "Delete Files"
        },
        "🔖 stash": {
          "description": "暂存文件",
          "title": "Stash Files"
        }
      }
    }
  },

安装并提交

方式一: 全局安装commitizen

# npm
npm install -g commitizen
# yarn
yarn add -g commitizen

git cz

方式二

npx cz

提交commit-msg

? Select the type of change that you're committing: 🚀 feat:     引入新功能
? What is the scope of this change (e.g. component or file name): (press enter to skip) 
? Write a short, imperative tense description of the change (max 91 chars):
 (3) abc
? Provide a longer description of the change: (press enter to skip)
 
? Are there any breaking changes? No
? Does this change affect any open issues? No

👆 至此,commit-msg 已经生成如果一切顺利,修改的内容就已经提交成功了。

💡 如果已经配置了上边的 commitlint 此时可能会报错,猜测可能commitlint不能识别emoji导致的。

⧗   input: 🚀 feat: "abc"
✖   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

🅰️ Angular 规范

Angular 规范的 commit-msg 包括三个部分:Header,Body 和 Footer。其中 Header 是必须的

Header

Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。

type

type用于说明 commit 的类别,只允许使用下面7个标识。

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

scope

scope 用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。

subject

subject是 commit 目的的简短描述,不超过50个字符。

  • 以动词开头,使用第一人称现在时,比如change,而不是changedchanges
  • 第一个字母小写
  • 结尾不加句号(.

Body

Body 部分是对本次 commit 的详细描述,可以分成多行。例如:

  • Bullet points are okay, too
  • Use a hanging indent

Footer

Footer 部分只用于两种情况。

不兼容变动

如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。

关闭 Issue

如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue ,可以关闭多个。例如:

Closes #123
Closes #123, #245, #992

Revert

Revert 是一种比较特殊的情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。Body部分的格式是固定的,必须写成This reverts commit <hash>.,其中的hash是被撤销 commit 的 SHA 标识符。例如:

revert: feat(pencil): add 'graphiteWidth' option

This reverts commit 667ecc1654a317a13331b17617d973392f415f02.