Skip to content

Git提交规范 Git Hook

提示

git hook 一般结合各种 lint,在 git 提交代码的时候进行代码风格校验,如果校验没通过,则不会进行提交。需要开发者自行修改后再次进行提交.

最有效的解决方案就是将 Lint 校验放到本地,常见做法是使用 husky 或者 pre-commit 在本地提交之前先做一次 Lint 校验。

自动配置husky (推荐)

yarn add husky --dev # must install

::: tabs

@tab npm

bash
npx husky-init && npm install

@tab Yarn 1

bash
npx husky-init && yarn

@tab:active Yarn 2

bash
yarn dlx husky-init --yarn2 && yarn

@tab:active pnpm

bash
pnpm dlx husky-init && pnpm install

::: 它将设置 husky,修改package.json并创建一个pre-commit您可以编辑的示例挂钩。默认情况下,它将npm test在您提交时运行。

把示例 npm test 修改成 yarn lint-staged 或者 您自己定义的命令

在 package.json中添加 lint-staged命令

text
"lint-staged": "lint-staged --allow-empty",
"lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ",
"lint-staged": {
    "**/*.{js,jsx,ts,tsx}": "yarn run lint-staged:js",
    "**/*.{js,jsx,tsx,ts,less,md,json}": [
      "prettier --write"
    ]
  },

在 git commit 的时候,就会触发 .husky/pre-commit 文件下 的命令行 yarn lint-staged或者 您自己定义的命令

在检查代码成功的时候会自动格式化代码然后帮您提交,如果检测到错误就会停止提交并告知错误行,及时改正后可以再次提交

快速配置

bash
npx mrm lint-staged

会自动安装 lint-staged 和 husky 并且在 package.json 里写入 lint-staged。

注意:mrm 是一个自动化工具,它将根据 package.json 依赖项中的代码质量工具来安装和配置 husky 和 lint-staged,因此请确保在此之前安装并配置所有代码质量工具,如 Prettier 和 ESlint。

如果上面顺利会在 package.json 里写入 lint-staged,可以自行修改让它支持 .vue 文件的校验:

text
{
    "lint-staged": {
        "*.{js,vue}": "eslint --cache --fix"
    }
}

启动 git hooks

bash
npx husky install

经过上面的命令后,v6 版本的 husky 会在项目根目录新建一个 .husky 目录。如果是 v4 版本的则会写入到 package.json 里。

创建 pre-commit 钩子

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

到这里后,git commit 前自动执行代码校验和修复的功能就算完成了。然后你可以试试修改文件,然后提交试试。

运行git commit时会自动调用husky添加的hook

提交代码时的检验 husky + lint-staged

只是单纯引入 eslint 校验如果不强制要求就等于没做,总会有人偷懒,所以还是要约束一下。

husky用于git执行钩子前做校验,我们只想校验我们自己提交的代码,这个时候就可以使用 husky,

lint-staged用于只校验git暂存区的文件。

这里要实现的功能是在git commit命令运行时先校验lint(包括eslint)是否通过,未通过则不予commit。

husky

husky 8.x 的使用参考 官网 husky-usage

推荐查看官网安装

手动安装

a. 初始化

text
// 初始化
npx husky-init && npm install

初始化后根目录会出现一个新目录 .husky 下面有 .husky/pre-commit 和 .husky/_/.husky.sh 等

b. 在安装后自动启用 Git 挂钩,请编辑 package.json

警告

注: 需要npm版本Version 7.x(npm set-script命令需要7.x)

ps: 执行yarn set-script prepare "husky install" 会报错:error Command "set-script" not found.

prepare 是 NPM 操作生命周期中的一环,在执行 install 的时候会按生命周期顺序执行相应钩子: NPM7: preinstall -> install -> postinstall -> prepublish -> preprepare -> prepare -> postprepare

bash
npm set-script prepare "husky install" && npm run prepare

配置如下

text
// package.json
{
  "scripts": {
    "prepare": "husky install"
  }
}

c.创建一条 pre-commit hook

将命令添加到钩子或创建新命令 husky add

bash
// 执行下面命令会 将命令添加到钩子或创建新命令,请使用 husky add <file> [cmd](不要忘记先运行 husky install)上面已经初始化过了。
npx husky add .husky/pre-commit "npm test"

执行该命令后,会看到.husky/目录下新增了一个名为pre-commit的shell脚本。

这样,在之后执行git commit命令时会先触发pre-commit这个脚本。

d. 开始测试

根据我们 eslint 配置好的校验,故意给我们的文件做个错误示例,看会不会 commit 时 自动执行 .husky/pre-commit 中写的指令 npm test 对我们的代码进行校验

笔者特地给 某个文件的 双引号 改为 单引号,然后配置一个没有 --fix 自动修复的指令, 当执行了

text
"scripts": {
  "test": "npm run lint",
  "lint:fix": "eslint --fix --ext .js,.vue src",
  "lint": "eslint --ext .js,.vue src",
},

当执行以下commit时

text
git add .
git commit -m "test husky pre-commit"

出现了报错, 提示应该根据 eslintrc 配置好的使用 单引号 singlequote

至此配置 husky 成功

提示

PS: 出错后可以继续使用 npm run lint:fix 修复错误

e. Uninstall(卸载husky)

bash
npm uninstall husky && git config --unset core.hooksPath

如何关闭

bash
# 删除husky依赖即可
yarn remove huksy

如何跳过某一个检查

有时候我们因为一些原因,想绕过hooks检查,可通过下方命令实现:

bash
# 加上 --no-verify即可跳过git hook校验(--no-verify 简写为 -n)
git commit -m "xxx" --no-verify

lint-staged

前面说了 lint-staged 用于只校验git暂存区的文件。在代码提交之前,进行代码规则检查能够确保进入git库的代码都是符合代码规则的。但是整个项目上运行lint速度会很慢

优点:lint-staged能够让lint只检测暂存区的文件,所以速度很快。 lint-staged过滤文件采用glob模式。

a. 安装 lint-staged

::: tabs

@tab npm

bash
npm i -D lint-staged

@tab Yarn

bash
yarn add lint-staged -D

:::

b. 配置 lint-staged

这里其实就是配置将我们上面配的 husky 执行 的lint 放到 lint-staged

git commit时触发pre-commit钩子,运行lint-staged命令,对*.js等执行eslint命令。eslint要提前配置好。

text
// package.json
"scripts": {
  "lint": "lint-staged", // 此处将之前的lint 改为 lint-stage的,将之前lint的指令放到 下面 lint-staged
},
"lint-staged": {
  "*.{js,vue}": [
      "eslint --ext .js,.vue src" // 执行eslint 校验
    // "git add" // 也可以执行 eslint --fix 这样直接配合 git add ,fix 后 重新 git add,我这里是有错误 直接 停止 --ext
  ]
}

再次模拟之前 的故意写个 错误的 eslint 示范,比如句尾加个 ';',或者改单引号为双引号,结果报错

提示

PS: 出错后可以继续使用 npm run lint:fix 修复错误

至此配置 lint-staged 成功

text
执行 npx lint-staged --help 命令可以看到相关的所有参数如下:

用法: lint-staged [options]

Options:
-V, --version                      输出版本号
--allow-empty                      当任务撤消所有分阶段的更改时允许空提交(默认值:false)
-c, --config [path]                配置文件的路径
-d, --debug                        打印其他调试信息(默认值:false)
-p, --concurrent <parallel tasks>  要同时运行的任务数,或者为false则要连续运行任务(默认值:true)
-q, --quiet                        自己的控制台输出(默认值:false)
-r, --relative                     将相对文件路径传递给任务(默认值:false)
-x, --shell                        跳过任务解析以更好地支持shell(默认值:false)
-h, --help                         输出用法信息


--allow-empty:使用此参数允许创建空的git提交。默认情况下,当LITER任务撤消所有阶段性的更改时,LITET阶段将抛出一个错误,并中止提交。

lint-staged 配置位于项目 .husky 目录下 lintstagedrc.js

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', 'stylelint --fix', 'prettier --write', 'git add .'],
	'*.{scss,less,styl,css,html}': ['stylelint --fix', 'prettier --write', 'git add .'],
	'*.md': ['prettier --write'],
}
text
	"prepare": "husky install",
text
	"husky": "^8.0.1",
	"lint-staged": "^13.0.3",
text
	"husky": {
		"hooks": {
			"pre-commit": "lint-staged"
		}
	},
	"lint-staged": {
		"./**/*.{js,vue,ts}": [
			"vue-cli-service lint --fix",
			"git add"
		]
	}

扩展 simple-git-hooks

https://www.5axxw.com/wiki/content/dcze0p

规范commit message信息

类似的,我们也可以添加commit-msg钩子,来规范我们的commit message信息

bash
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
  • 安装 commitlint
bash
npm i @commitlint/cli @commitlint/config-conventional -D
  • 配置 commitlint.config.js
bash
echo "module.exports = {extends: ['@commitlint/config-conventional']};" > commitlint.config.js

commit-msg 在此阶段,可用 @commitlint/cli @commitlint/config-conventional 对提交信息进行验证。但是记信息格式规范真的太太太太麻烦了,所以可用 commitizen cz-git 生成提交信息。

执行yarn add @commitlint/cli @commitlint/config-conventional -D安装commitlint相关依赖,用来帮助我们在多人开发时,遵守 git 提交约定。

执行echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js在根目录创建 commitlint.config.js 文件(当然也可以手动创建此文件),其内容如下所示:

js
module.exports = {
	extends: [
		'@commitlint/config-conventional'
	],
	// 以下时我们自定义的规则
	rules: {
		'type-enum': [
			2,
			'always',
			[
				'bug', // 此项特别针对bug号,用于向测试反馈bug列表的bug修改情况
				'feat', // 新功能(feature)
				'fix', // 修补bug
				'docs', // 文档(documentation)
				'style', // 格式(不影响代码运行的变动)
				'refactor', // 重构(即不是新增功能,也不是修改bug的代码变动)
				'test', // 增加测试
				'chore', // 构建过程或辅助工具的变动
				'revert', // feat(pencil): add ‘graphiteWidth’ option (撤销之前的commit)
				'merge' // 合并分支, 例如: merge(前端页面): feature-xxxx修改线程地址
			]
		]
	}
}

执行yarn husky add .husky/commit-msg 'yarn commitlint --edit "$1"'之后,会看到在根目录的.husky文件夹下多了一个 commit-msg 文件,其内容如下:

bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn commitlint --edit "$1"

紧接着,我们需要将上一步添加的钩子添加到git中去,执行git add .husky/commit-msg

执行yarn husky add .husky/pre-commit 'yarn lint-staged --allow-empty "$1"'之后,会看到在根目录的.husky文件夹下多了一个 pre-commit 文件,其内容如下:

bash
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn lint-staged --allow-empty "$1"

同样的,我们需要将上一步添加的钩子添加到git中去,执行git add .husky/pre-commit

yorkie

fork自husky,做了一些改动,如下:

优先考虑位于.git目录旁边的package.json,而不是硬编码的向上搜索。避免了在lerna 仓库中的根包和子包都依赖于husky的问题,它会混淆并用错误的路径,双重更新根git钩子。

更改在package.json中hooks的位置

text
before:
{
  "scripts": {
    "precommit": "foo"
  }
}

After:
{
  "gitHooks": {
    "pre-commit": "foo"
  }
}

安装

vue脚手架vue-cli在初始化完项目后,@vue/cli-service 会自动安装 yorkie,它会让你在 package.json 的 gitHooks 字段中方便地指定 Git hook:

text
{
  "gitHooks": {
    "pre-commit": "lint-staged" // 配置脚本
  },
   "lint-staged": {
    "*.{js,vue}": [
      "vue-cli-service lint",
      "git add"
    ]
  }
}

husky与yorkie的不同

husky v7版本仅支持修改.husky/xxx目录下的配置脚本,v4版本支持package.json中通过husky: {hooks: {"pre-commit": xxx} }的方式更新脚本

yorkie支持在package.json中通过"gitHooks": {"pre-commit": xxx}的方式更新脚本。

yorkie fork 自 husky 并且与后者不兼容。

安装husky依赖及初始化

text
pnpm add husky -Dw

# 初始化husky
npx husky install

# 添加 pre-commit hooks
npx husky add  .husky/pre-commit "npx lint-staged"

# 添加 commit-msg hooks
npx husky add  .husky/commit-msg 'npx --no -- commitlint --edit "$1"'

安装lint-staged依赖 pnpm add lint-staged -Dw 复制代码 .lintstagedrc

text

{
"packages/**/*.{vue,ts,js}": [
"eslint --fix"
]
}

安装commitlint相关依赖及配置

bash
pnpm add @commitlint/cli @commitlint/config-conventional commitlint-config-cz cz-customizable -Dw

package.json

text
{
// ...
  "scripts":{
      "commit": "node ./node_modules/cz-customizable/standalone.js",
      "preinstall": "npx only-allow pnpm"
   },
// ...
}

.commitlintrc

text
{
"extends": ['@commitlint/config-conventional', 'cz']
}

汉化默认的commit提示 .cz-config.js

js
module.exports = {
	types: [
		{ value: 'feat', name: '✨ Features | 新功能' },
		{ value: 'fix', name: '🐛 Bug Fixes | Bug 修复' },
		{ value: 'init', name: '🎉 Init | 初始化' },
		{ value: 'docs', name: '✏️ Documentation | 文档' },
		{ value: 'style', name: '💄 Styles | 风格' },
		{ value: 'refactor', name: '♻️ Code Refactoring | 代码重构' },
		{ value: 'perf', name: '⚡ Performance Improvements | 性能优化' },
		{ value: 'test', name: '✅ Tests | 测试' },
		{ value: 'revert', name: '⏪ Revert | 回退' },
		{ value: 'build', name: '📦‍ Build System | 打包构建' },
		{ value: 'chore', name: '🚀 Chore | 构建/工程依赖/工具' },
		{ value: 'ci', name: '👷 Continuous Integration | CI 配置' }
	],

	// scopes: [{ name: 'accounts' }, { name: 'admin' }, { name: 'exampleScope' }, { name: 'changeMe' }],

	allowTicketNumber: false,
	isTicketNumberRequired: false,
	ticketNumberPrefix: 'TICKET-',
	ticketNumberRegExp: '\\d{1,5}',

	// it needs to match the value for field type. Eg.: 'fix'

	scopeOverrides: {
		fix: [
			{ name: 'merge' },
			{ name: 'style' },
			{ name: 'e2eTest' },
			{ name: 'unitTest' }
		]
	},

	// override the messages, defaults are as follows
	messages: {
		type: '选择要提交的更改类型:',
		scope: '\n表示此更改的范围(可选):',
		// used if allowCustomScopes is true
		customScope: '表示此更改的范围(自定义):',
		subject: '写一个简短的,命令式的时态描述变化:\n',
		body: '提供更改的较长描述(可选)。使用"|"换行:\n',
		breaking: '列出任何重大更改(可选):\n',
		footer: '列出此更改关闭的任何问题(可选). E.g.: #31, #34:\n',
		confirmCommit: '您确定要继续上面的提交吗?',
	},

	allowCustomScopes: true,
	allowBreakingChanges: ['feat', 'fix'],
	// skip any questions you want
	skipQuestions: ['body'],

	// limit subject length
	subjectLimit: 100,
// breaklineChar: '|', // It is supported for fields body and footer.
// footerPrefix : 'ISSUES CLOSED:'
// askForBreakingChangeFirst : true, // default is false
}

Husky 不起作用解决方案

参考官网:https://typicode.github.io/husky/#/ 按以下步骤进行设置:

删除 .git 目录下的 hooks 及 .husky

查看 git config 配置是否存在 core.hookspath=.husky

bash
git config --list

删除配置及卸载 Huksy:

bash
npm uninstall husky && git config --unset core.hookspath

再次安装 Husky:

bash
npm install husky --save-dev
// npm set-script prepare "husky install"
npx husky-init

新增 Hooks:

bash
npx husky add .husky/pre-commit "npx lint-staged"
npx husky add .husky/pre-commit "npx pretty-quick --staged"
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit'

Contributors

作者:Long Mo
字数统计:3.4k 字
阅读时长:13 分钟
Long Mo
文章作者:Long Mo
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Longmo Docs