Skip to content
快速预览

git限制提交

✍️ w 🕒 2023-09-19 09:31:13(8 months ago) 🔗 C.前端工程化

提交前当我们使用git 等这类工具的时候,在提交的时候做最后一道防护,防止团队成员提交的代码风格和团队不同

当我们使用版本控制系统(如Git)管理代码时,可以通过钩子(hooks)来在特定的时间点执行自定义的脚本或命令。在Git中,有多个钩子可供使用,其中包括以下四个常用的钩子,以下是对Git钩子(hooks)中的四个主要提交阶段的整理和进一步说明:

pre-commit(提交前钩子)

pre-commit(提交前钩子),在执行真正的提交操作之前运行的钩子当我们执行 git commit 命令提交代码时,Git会在实际进行提交操作之前触发 pre-commit 钩子

作用

  • 在实际提交操作之前运行。
  • 用于执行代码检查工具(如静态代码分析、代码风格检查等)。
  • 确保提交的代码符合一定的质量标准。

示例用途

  • 检查代码是否符合项目的编码规范。
  • 检测潜在的编程错误或安全漏洞。
  • 如果检查未通过,可以返回非零值阻止提交。

prepare-commit-msg(准备提交信息钩子)

prepare-commit-msg(准备提交信息钩子),是 Git 的一个钩子(hook),它允许您在提交信息被最终保存之前对其进行操作或修改,当您执行 git commit 命令时,prepare-commit-msg 钩子会在编辑器打开提交信息之前被触发。

作用

  • 在Git生成默认提交信息后,启动编辑器之前运行。
  • 对提交信息进行预处理。
  • 加载辅助填写工具,如Commitizen。

示例用途

  • 修改或添加到默认的提交信息。
  • 加载工具来帮助编写符合规范的提交信息。
  • 提高提交信息的一致性和可读性。

commit-msg(提交信息钩子)

commit-msg(提交信息钩子) ,在完成提交信息的编辑后运行的钩子。它允许我们对提交信息进行进一步的检查或处理。常用的用途是使用提交信息规范工具(如commitlint)对提交信息进行验证,以确保其符合预定义的规范

作用

  • 在完成提交信息的编辑后运行。
  • 对提交信息进行进一步的检查或处理。
  • 使用工具(如commitlint)验证提交信息。

示例用途

  • 确保提交信息符合预定义的规范。
  • 提高提交信息的一致性。
  • 帮助团队成员更好地理解提交的目的和内容。

post-commit(提交后钩子)

post-commit(提交后钩子),在提交操作完成后运行的钩子。这个阶段通常用于执行一些与提交相关的通知或后续操作。例如,我们可以在这个钩子中发送通知(如Slack消息)给团队成员,告知他们有新的提交。也可以在这个阶段触发自动化部署流程,将提交的代码部署到相应的环境中。

作用

  • 在提交操作完成后运行。
  • 执行与提交相关的通知或后续操作。

示例用途

  • 发送通知(如Slack消息)给团队成员。
  • 触发自动化部署流程。
  • 将提交的代码部署到相应的环境中。

通过使用这些钩子,我们可以在不同的阶段对提交流程进行自定义操作,从而实现代码质量控制、规范化提交信息、自动化通知等功能,提高开发团队的协作效率和代码管理质量。

如何利用 git hooks 钩子

直接去改动git hook是不明智因为改动本地的钩子是无法同步到远程仓库的git 钩子上

因此可以使用 Husky 是一个 Git hooks 工具,它允许你在项目中配置钩子脚本。Git 钩子是在特定的 Git 事件发生时触发的自定义脚本。这些事件可以是提交代码、推送到远程仓库、合并分支等。

husky是一个Git hooks工具,能够在项目中配置hooks脚本;当我们执行git操作时,自动触发配置的脚本;并且在指定git hook 钩子去配置要执行的脚

使用 husky

bash
npm install -D husky
  • 在6.0版本之前安装 之后 只需要在package.json 中去配置对应git hook 生命周期触发的钩子即可
js
{
  "husky": {
    "hooks": {
      "pre-commit": "npm run test", // 在commit之前先执行npm run test命令
      "commit-msg": "commitlint -e $HUSKY_GIT_PARAMS" // 校验commit时添加的备注信息是否符合我们要求的规范
    }
  }
}
  • 在 6.0 之后 已经不用在package.json 中去配置
bash
npm install -D husky

执行以下命令来初始化 Husk 会帮我们创建 .husky 文件并不会帮助创建git hook钩子配置文件,你需要手动添加和配置钩子

当你想要完全自定义 Husky 的配置,并手动设置钩子时 可以采用这个执行脚本

bash
npx husky install

此时 Husky 会修改 Git 配置,将 Git 钩子的目录指向 .husky。这意味着当执行特定的 Git 操作(如 commit、push 等)时,Git 会查找 .husky 目录中的相应钩子脚本并执行它。

使用 npx husky add 命令来轻松地为特定的 Git 操作(如 pre-commit、pre-push 等)添加钩子脚本

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

在实际项目时候更推荐执行脚本,创建 .husky 目录,并在其中生成一个示例的 pre-commit 钩子。可能还会生成一些示例代码和依赖。

bash
npx husky-init

解决多人开发的时候 husk 初始化

要考虑的另一个问题是 如何保证多人维护的时候 其他人使用代码时候,能够 去主动触发 npx husky install 将 Git 钩子的目录指向 .husky

这意味着当执行特定的 Git 操作(如 commit、push 等)时,Git 会查找 .husky 目录中的相应钩子脚本并执行它

可以使用 package.json 文件中设置一个名为 "prepare" 的脚本,该脚本会在项目并运行 npm install 时,"prepare" 脚本会自动执行。因此可以利用这个性质 确保了 Husky 钩子在项目依赖安装后正确安装 husky install 来替换git hooks 钩子的作用

执行npm set-script prepare "husky install" 只是 npm7.x 支持的命令,如果你是7.x 之前的版本你可以直接在package.json中添加prepare脚本

如果执行时候提示 npm WARN set-script set-script is deprecated, use npm pkg set scripts.scriptname="cmd" instead. 你需要使用新的指令 npm pkg set scripts.prepare="husky install"

json
{
  "scripts": {
    "prepare": "husky install"
  }
}

此时 当我们执行npm install安装完项目依赖后会执行husky install命令,该命令会创建 .husky/目录并指定该目录为git hooks所在的目录

配置钩子的脚本

上面使用 husky 库来接管了 git hooks ,接下来就要在 接管后映射的文件目录.husky 去编写各个环境脚本

配置pre-commit 钩子 对代码格式化

在这个钩子用于执行代码检查工具(如静态代码分析、代码风格检查等)。确保提交的代码符合一定的质量标准。最简单的方法只要在这个钩子触发的阶段,去触发我们在 package.json 中用来个格式化检查代码的配置 scripts 脚本,例如下面 prettier 的脚本

json
"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "prettier": "prettier --write .",
    "prepare": "husky install",
    "commit": "cz"
  },

但这里要注意一个优化,prettier 或者配置的类似的其他 脚本 往往他们都是对全局代码进行了一次格式化,这其实并是我们需要的

我们只要对暂存的文件进行检查 格式化即可 这时候就需要 使用lint-staged是一个对git暂存区代码进行格式化的工具

使用 lint-staged,你可以定义一系列要运行的任务和相关的文件匹配规则。当你执行 git commit 时,lint-staged 会自动检查暂存区内的文件,并根据配置规则运行相应的任务。如果某些文件未通过任务的检查,lint-staged 会阻止提交,以便你有机会修复这些问题

安装

bash
npm install lint-staged --save-dev

package.jsonscripts 脚本 配置能运行 lint-staged指令,或者执行 npm pkg set scripts.lint-staged="lint-staged"

json
// change 1: 配置lint-staged指令
"scripts": {
    // 新增这一行
    "lint-staged": "lint-staged",
    ...
},

因此在 pre-commit 钩子执行的脚本就要变成 lint-staged, lint-staged 中要执行脚本编写到 package.json 的 "lint-staged"

json
// change 2: 配置lint-staged的具体任务
 "lint-staged": {
    "*.{js,jsx,ts,tsx}": [
      "eslint --fix",
      "prettier --write"
    ],
    "{!(package)*.json,*.code-snippets,.!(browserslist)*rc}": [
      "prettier --write--parser json"
    ],
    "package.json": [
      "prettier --write"
    ],
    "*.vue": [
      "eslint --fix",
      "prettier --write",
      "stylelint --fix"
    ],
    "*.{scss,less,styl,html}": [
      "stylelint --fix",
      "prettier --write"
    ],
    "*.md": [
      "prettier --write"
    ]
  },

添加一个 pre-commit 钩子来运行 lint-staged:

bash
npx husky add .husky/pre-commit "npx lint-staged"

备注:关于 lint-staged 也可以做单独的文件配置,在package.json 中的脚本配置指向文件

json
"scripts": {
		"lint:lint-staged": "lint-staged -c ./.husky/lintstagedrc.js",
 }

lintstagedrc 文件内容

js
module.exports = {
 '*.{js,jsx,ts,tsx}': ['eslint --fix', 'prettier --write'],
 '{!(package)*.json,*.code-snippets,.!(browserslist)*rc}': ['prettier --write--parser json'],
 'package.json': ['prettier --write'],
 '*.vue': ['eslint --fix', 'prettier --write', 'stylelint --fix'],
 '*.{scss,less,styl,html}': ['stylelint --fix', 'prettier --write'],
 '*.md': ['prettier --write'],
};

commit-msg(提交信息钩子)

Commit message 是开发者在 Git 提交代码时对提交进行描述的信息,它通常包括一个简短的标题和一个可选的详细描述。使用一致和规范的 Commit message 格式可以提高代码库的可读性、可维护性和协作效率

安装@commitlint/config-conventional@commitlint/cli 是两个不同的包,各自承担着不同的角色,通常需要配合使用,以便实现完整的提交消息规范和验证流程。

shell
npm i @commitlint/config-conventional @commitlint/cli -D
  1. @commitlint/config-conventional:

    • 这个包主要用于定义和配置 Conventional Commits 规范,规定了提交消息的格式和规则,但它本身不会执行验证
    • @commitlint/config-conventional 仅提供规范的配置信息,以告诉验证工具如何验证提交消息。
  2. @commitlint/cli:

    • 这个包是一个命令行工具,用于在 Git 提交时验证提交消息是否符合规范
    • @commitlint/cli 实际执行验证操作,检查提交消息是否符合 @commitlint/config-conventional 中定义的规范。
    • 它还可以与 Git 钩子一起使用,以便在提交代码之前自动运行验证,以确保每个提交都遵循规范。

综合来说,@commitlint/config-conventional 是规范的定义者,而 @commitlint/cli 是规范的执行者

它们一起协作,使得团队能够实施和强制提交消息的规范,从而确保提交历史的一致性和可读性。使用 @commitlint/cli 可以在提交前自动检查提交消息,防止不符合规范的提交进入代码库,有助于维护代码质量和协作效率。

在根目录创建commitlint.config.js文件,配置commitlint ,我们告诉 commitlint 在验证提交信息时应该使用 @commitlint/config-conventional 规范配置中定义的规则

通过这样的配置,当你使用 commitlint 进行提交信息验证时,它会根据 @commitlint/config-conventional 规范配置对提交信息进行检查,确保它们符合约定的格式和规范。如果提交信息不符合规范,commitlint 将会给出相应的错误或警告信息,以便你进行修正

js
module.exports = {
  extends: ['@commitlint/config-conventional'],
  rules: {
    'type-enum': [
      2,
      'always',
      [
        '新功能', // 添加新功能
        '修复', // 修复 bug
        '文档', // 文档变更
        '样式', // 样式变更
        '重构', // 代码重构
        '性能', // 性能优化
        '测试', // 添加或修改测试代码
        '构建', // 构建过程或工具变动
        '配置', // 配置文件变动
        '版本', // 版本号变更
        '回滚', // 代码回滚
        '其他' // 其他变更
      ]
    ],
    'type-case': [0], // 类型大小写不作要求
    'type-empty': [0], // 类型不能为空
    'subject-max-length': [2, 'always', 100], // 主题最大长度为 100
    'subject-case': [0], // 主题大小写不作要求
    'subject-empty': [2, 'never'], // 主题不能为空
    'body-max-line-length': [2, 'always', 100], // 详细描述每行最大长度为 100
    'footer-max-line-length': [2, 'always', 100] // 关联问题每行最大长度为 100
  }
};

使用husky生成commit-msg文件,验证提交信息:

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

上面的这种标准化的提交形式格式如果每次在提交时候手动来编写这些是比较麻烦的事情,我们可以使用一个工具:Commitizen

  • Commitizen 基于Node.js的 git commit 命令行工具,辅助生成标准化规范化的 commit message;

1.安装Commitizen

shell
npm install commitizen -D

2.安装cz-conventional-changelog,并且初始化cz-conventional-changelog:cz-conventional-changelog 是一个用于生成符合规范的提交信息的 Commitizen 插件。它提供了一种交互式的方式来帮助开发者按照规范格式化和填写提交信息,并生成符合规范的提交记录,以便于后续使用工具生成变更日志

cz-conventional-changelog 基于 commitlint 的规范配置,使用了 @commitlint/config-conventional 规范作为提交信息的模板。它要求开发者按照特定的格式填写提交信息,包括类型、范围、主题等,并可以选择关联的问题或任务。

shell
npx commitizen init cz-conventional-changelog --save-dev --save-exact

这个命令会帮助我们安装cz-conventional-changelog,并且在package.json中进行配置:

json
{
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  }
}

这个时候我们提交代码需要使用 npx cz 或者 运行 git cz 命令来代替 git commit,按照交互式提示填写提交信息

  • 第一步是选择type,本次更新的类型
Type作用
feat新增特性 (feature)
fix修复 Bug(bug fix)
docs修改文档 (documentation)
style代码格式修改(white-space, formatting, missing semi colons, etc)
refactor代码重构(refactor)
perf改善性能(A code change that improves performance)
test测试(when adding missing tests)
build变更项目构建或外部依赖(例如 scopes: webpack、gulp、npm 等)
ci更改持续集成软件的配置文件和 package 中的 scripts 命令,例如 scopes: Travis, Circle 等
chore变更构建流程或辅助工具(比如更改测试环境)
revert代码回退
  • 第二步选择本次修改的范围(作用域)

  • 第三步选择提交的信息

  • 第四步提交详细的描述信息

  • 第五步是否是一次重大的更改

  • 第六步是否影响某个open issue

我们也可以在scripts中构建一个命令来执行 cz:

json
"scripts": {
	"commit": "cz"
}

注意 方案中的 cz-conventional-changelog 其实已经不推荐了,可以参考

可以使用 可以使用 cz-git-cli 注意 cz-git-cli 和 cz-git 不一样的 cz-git-cli 来替代 commitizen,而cz-git 事用来替代 cz-conventional-changelog


参考

用Eslint+Prettier+husky+commitlint+lint-staged+commitizen快速搭建标准化编程规范项目

Released under the MIT License.