新版 husky 配置与Git Hooks剖析
前端工程化 —— husky
分享近期配置 husky 的一些心得
husky
husky 是前端工程化不可缺少的工具,它支持添加项目的 git hooks(可以理解当我们使用 git 命令操作时会触发的钩子事件),如此一来我们就能在提交代码时:
配合 commitlint | lint-staged & ESlint & Stylelint,对提交信息进行检查 | 运行测试 | 检查代码格式与是否报错。
我还记得在我实习的时候,我老大就经常会进行前端工程化的工作,将我们几个实习生的代码规范和开发流程严格把控,时间长了对这几个前端工程化工具慢慢就会熟悉。这恰恰是一个开发团队需要的开发规范。这几天我也需要搭建一个新的项目但是发现 husky 的配置和原来有很大的不一样。
(4.*) 旧版玩法
1. 下载依赖
npm install -D husky@^4.3.0
yarn add -D husky@^4.3.0
2. 配置
在 package.json 中配置
husky属性
{
"husky": {
"hooks": {
"pre-push": "npm run test",
"commit-msg": "commitlint --config -E HUSKY_GIT_PARAMS"
}
}
}
- 这样在你执行
git commit的时候就会自动执行commitlint命令。即把你的commit信息赋值给HUSKY_GIT_PARAMS作为参数传入commitlint命令进行校验。 - 这里可以看出旧版主要是利用
package.json进行git钩子信息获取。
(7.*) 新版玩法
1. 下载依赖
npm install -D husky
yarn add -D husky
2. 配置
在 package.json 中配置
scripts添加属性
{
"scripts": {
"prepare": "husky install"
}
}
新版 husky 提供命令来添加 git 钩子事件 ——
husky add <file> [cmd],即执行下面的命令
npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
npx husky add .husky/pre-push "npm run test"
prepare是NPM操作的生命周期的一环,即当我们执行npm install时会按照生命周期以此触发生命周期钩子,在NPM7:preinstall -> install -> postinstall -> prepublish -> preprepare -> prepare -> postprepare- 这里可以发现
commit-msg和pre-push和旧版配置中有点眼熟,这两个恰恰都是我们就是执行git命令钩子事件名 Git Hooks
新版剖析
git hooks一共有两种方式创建:
- 第一种就是旧版的在
.git/hooks文件夹中创建对应事件名的脚本文件 - 第二种就是定义
hooksPath配置指向 hooks 文件夹
为什么抛弃传统js的写法
作者写的文章:链接
- 创建了所有的
git hooks:旧版正是 git hooks 创建方式的第一种- 好处:用户不需要关心 git hooks类型,只需要在
package.json配置命令即可 - 坏处:每次执行 git 操作时所有的
git hooks都会挨个执行
- 好处:用户不需要关心 git hooks类型,只需要在
- 没办法按需引入
git hooks:当用户对package.json进行添加操作后,没办法同步添加.git/hooks对应的钩子文件。 - 太局限,用户自定义困难:比如我有需求在命令行当中利用钩子进行构建,生成文件,读取文件信息等需要大量
shell命令时,对于一个天天接触 shell 的我而言只能写单一脚本的传统的package.json写法 太局限了,会很难受。
e.g: 输出一些信息:

上图示例代码
#!/bin/sh
# 在新版中可以很舒服的写 shell 脚本
. "$(dirname "$0")/_/husky.sh"
printf "\n\033[1;32m%s \033[1;33m%s \033[1;32m%s\033[0m\n" \
"»»»" \
"commitlint checking..." \
"«««"
yarn commitlint --edit "$1"
新版是什么原理
- git config 的
core.hooksPath。在2016年git 2.9版本引入新feature,hooksPath属性可以支持设置 Git Hooks 文件夹指向。我们可以打开.git/.config文件看看:
- 新版顺利安装后我们会得到一个文件夹正是
.husky:
$ x ls -T .husky/ -a
.husky
├── _
│ ├── .gitignore
│ └── husky.sh
├── commit-msg
└── pre-commit
- 从这里开始他的设计已经明了:定义了Git Hooks 指向文件夹后,每当我们使用 git 命令的执行时会去对应文件夹下寻找与钩子事件名同名的文件进行source,这个设计和我们 x-cmd 的workspace script设计很像。
- 至于新版的commit-msg命令中的
$1进行输出确认是.git/COMMIT_EDITMSG文件: 即最近一次的commit edit message。
总结
- 其实新版这个设计对于小白添加了一定难度,但是对于项目上的设计放开的局限性。husky的目的也达到了:作为项目管理上的 git hooks 的入口。
- 立个flag,我相信我们X-Cmd团队会在不远的将来有一套方案和他竞争 😎
旧版迁移新版
- 删除项目当中的
.git/hooks文件夹、 - 删除package.json的
husky属性 - 执行上面新版的操作
Git Hooks
除了
commit-msg和pre-commit还有什么git hooks ? 文档
| Git Hook | 调用时机 | 说明 |
|---|---|---|
| pre-applypatch | git am执行前 | |
| applypatch-msg | git am执行前 | |
| post-applypatch | git am执行后 | 不影响git am的结果 |
| pre-commit | git commit执行前 | 可以用git commit --no-verify绕过 |
| commit-msg | git commit执行前 | 可以用git commit --no-verify绕过 |
| post-commit | git commit执行后 | 不影响git commit的结果 |
| pre-merge-commit | git merge执行前 | 可以用git merge --no-verify绕过。 |
| prepare-commit-msg | git commit执行后,编辑器打开之前 | |
| pre-rebase | git rebase执行前 | |
| post-checkout | git checkout或git switch执行后 | 如果不使用--no-checkout参数,则在git clone之后也会执行。 |
| post-merge | git commit执行后 | 在执行git pull时也会被调用 |
| pre-push | git push执行前 | |
| pre-receive | git-receive-pack执行前 | |
| update | ||
| post-receive | git-receive-pack执行后 | 不影响git-receive-pack的结果 |
| post-update | 当 git-receive-pack对 git push 作出反应并更新仓库中的引用时 | |
| ... |
I just try my best to make thing well, Could you give a star ⭐ to encourage me ?
- (4.*) 旧版玩法
- 1. 下载依赖
- 2. 配置
- (7.*) 新版玩法
- 1. 下载依赖
- 2. 配置
- 新版剖析
- 为什么抛弃传统js的写法
- 新版是什么原理
- 总结
- 旧版迁移新版
- Git Hooks