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