分享近期配置 husky 的一些心得

husky


Github · 文档


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"
  • prepareNPM 操作的生命周期的一环,当我们执行 npm install 时会按照生命周期以此触发生命周期钩子,在NPM7:preinstall -> install -> postinstall -> prepublish -> preprepare -> prepare -> postprepare
  • 这里可以发现 commit-msgpre-push 和旧版配置中有点眼熟,这两个恰恰都是我们就是执行git命令钩子事件名 Git Hooks

新版剖析


git hooks一共有两种方式创建:

  1. 第一种就是旧版的在 .git/hooks 文件夹中创建对应事件名的脚本文件
  2. 第二种就是定义 hooksPath 配置指向 hooks 文件夹

为什么抛弃传统js的写法

作者写的文章:链接

  1. 创建了所有的 git hooks :旧版正是 git hooks 创建方式的第一种
    • 好处:用户不需要关心 git hooks类型,只需要在 package.json 配置命令即可
    • 坏处:每次执行 git 操作时所有的 git hooks都会挨个执行
  2. 没办法按需引入 git hooks:当用户对 package.json 进行添加操作后,没办法同步添加 .git/hooks对应的钩子文件。
  3. 太局限,用户自定义困难:比如我有需求在命令行当中利用钩子进行构建,生成文件,读取文件信息等需要大量 shell 命令时,对于一个天天接触 shell 的我而言只能写单一脚本的传统的 package.json写法 太局限了,会很难受。

e.g: 输出一些信息:

e.g-img

上图示例代码
#!/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"

新版是什么原理

  1. git config 的core.hooksPath。在2016年 git 2.9 版本引入新featurehooksPath属性可以支持设置 Git Hooks 文件夹指向。我们可以打开 .git/.config文件看看: git config
  2. 新版顺利安装后我们会得到一个文件夹正是.husky
$  x ls -T .husky/ -a
.husky
├── _
│  ├── .gitignore
│  └── husky.sh
├── commit-msg
└── pre-commit
  1. 从这里开始他的设计已经明了:定义了Git Hooks 指向文件夹后,每当我们使用 git 命令的执行时会去对应文件夹下寻找与钩子事件名同名的文件进行source,这个设计和我们 x-cmd 的workspace script设计很像。
  2. 至于新版的commit-msg命令中的 $1 进行输出确认是 .git/COMMIT_EDITMSG 文件: 最近一次的commit edit message。

总结

  • 其实新版这个设计对于小白添加了一定难度,但是对于项目上的设计放开的局限性。husky的目的也达到了:作为项目管理上的 git hooks 的入口
  • 立个flag,我相信我们X-Cmd团队会在不远的将来有一套方案和他竞争 😎

旧版迁移新版


  1. 删除项目当中的 .git/hooks 文件夹、
  2. 删除package.json的 husky 属性
  3. 执行上面新版的操作

Git Hooks


除了 commit-msgpre-commit 还有什么git 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 作出反应并更新仓库中的引用时
...


I just try my best to make thing well, Could you give a star ⭐ to encourage me ?

我是 Qbenben,一个爱折腾在沉浸在代码世界打怪升级的深圳小靓仔,感谢您的阅读。Github · Blog