husky钩子的一些用法
前言
husky是一个npm包,可以将git内置的钩子暴露出来,很方便地进行钩子的命令注入,而不需要在.git目录下自己写shell脚本了;不仅可以执行js文件作为脚本,还可以将脚本暴露出来,方便在git项目中进行管理。
基本用法
原理
husky支持的钩子就是git hooks,可以在对应钩子指定一条shell命令,husky会自动将这个命令写入.git目录下的对应钩子脚本,当触发这个git钩子时则会执行我们写入的命令;
因此husky本质上就是执行shell命令,因此只要是shell命令都可以在钩子中执行;由于nodeJS也可以通过命令行执行,所以直接用js来充当脚本也是可以的;
命令配置
可以在package.json文件的husky.hooks对象中写入相应的命令即可,键名就是钩子名称,键值就是需要执行的命令,如:
1 | { |
husky当然也支持通过专门的配置文件来指定钩子命令,但是使用过程中经常发生钩子配置不起作用的情况,还是package.json这种方式最稳定;
常用钩子
pre-commit:由git commit命令触发,在commit-msg之前;commit-msg:git commit和git merge都会触发,会传递一个参数,该参数为存放当前commit消息的临时文件路径;可以通过--no-verify参数来跳过commit-msg钩子;post-merge:触发于merge完成后;
一些技巧
在 node 脚本中如何退出
当使用node脚本进行检测,希望检测不通过时阻止git进行下一步操作,即终止操作;仅仅抛出错误是不能终止命令的,只能抛出exit状态才能终止;如:
1 | process.exit(1) // exit状态为1才能终止 |
在 node 中执行 shell 命令
有些用于检测的信息只能通过shell命令执行获取(如git相关的信息),如果想要在node中获取到这些信息,可以使用node自带的一些方法来执行;比如exec和spawn方法。
上面两个都是child_process模块里面的方法:
1 | const { spawn, exec } = require('child_process') |
虽然这两个方法都可以执行shell命令,但是具体用途有所不同;就作用而言,spawn方法更加广泛,可控性更强;
- 当仅仅需要执行
shell命令来获取信息(文本)时,可以使用exec方法; - 如果需要按照原格式(即包含颜色,缩进,换行等)暴露
shell命令的标准输出,那么就需要用到spawn方法了;因为exec得到的标准输出已经格式化了,仅仅是普通的文本字符串;
可以将上述方法包装成Promise对象,这样更加方便进行同步调用:
1 | /** |
在 commit-msg 钩子中获取/修改 commit 消息
执行commit命令后,git会将commit消息存放于一个临时文件中;然后触发pre-commit钩子,pre-commit钩子成功之后就会触发commit-msg,commit-msg钩子成功后则会将临时文件中的文本作为此次commit消息进行存储;
并且commit-msg钩子会对脚本传一个参数,这个参数就是存放commit消息的临时文件的路径;所以得到这个参数,就可以读取该文件的内容,也就能得到当前commit消息了;同理,在commit-msg钩子中覆盖这个文件就能对此次commit消息进行修改了;
It takes a single parameter, the name of the file that holds the proposed commit log message.[1]
不过,由于在husky中的指定的commit-msg钩子命令并不是git直接执行的,因此只能通过husky间接暴露的变量$HUSKY_GIT_PARAMS来获取临时文件的地址,如:
1 | # $HUSKY_GIT_PARAMS变量就是commit-msg钩子传递的文件路径参数 |
Git hooks can get parameters via command-line arguments and stdin. Husky makes them accessible via HUSKY_GIT_PARAMS and HUSKY_GIT_STDIN environment variables.[2]
在node脚本内部就可以利用process.argv来获取命令行参数了;
1 | const param = process.argv[process.argv.length - 1] // 获取git commit消息临时存放文件地址 |
读取和写入操作既可以依靠node自带的方法,也可以利用shell命令(shell命令简单粗暴);
钩子没有触发
当第一次安装husky的时候,可能会出现.git/hooks里面的文件没有被覆盖的情况;此时,git hooks仍然是之前的状态(默认是没有效果的);如果是husky安装正常,使用命令ls .git/hoooks查看文件则是下面这样:

随便打开一个钩子脚本文件,内容可能是这样:
1 |
|
如果不是上述形式,那么就是husky注入失败;可以通过重新安装(先uninstall再install)进行重新注入,因为每次安装husky时会重新覆盖一次.git/hooks脚本文件。
可用 shell 命令收集
获取当前 git 分支名称
1 | git symbolic-ref --short -q HEAD |
获取最新的一条 git 提交信息
1 | git rev-list --no-walk --header HEAD |
可以得到很详细的信息,用于进一步检测,比如检测最新的一次提交是不是merge,merge行为是否合法等待;
1 | 635a70d8e1eaccfe7a460e76ae400a0e5cc95161 |
读取或写入文件
读取使用cat命令:
1 | cat file-path |
写入使用echo命令:
1 | echo "content" > file-path |
相关文档
- Git - githooks Documentation
- inanzzz | Automatically amending the commit message with commit-msg hook
- javascript - Retaining output colors when shelling out to node - Stack Overflow:输出原格式的来源
- git rev-list (Plumbing Commands) - Git 中文开发手册 - 开发者手册 - 云+社区 - 腾讯云:
rev list命令文档,该命令十分强大 - Husky cannot execute hooks · Issue #445 · typicode/husky · GitHub