你将学到什么?
你将学习到husky的原理。
了解git-hook, npm-hook。
1. Git hooks 的使用
git 可以在特定动作发生时触发自定义脚本。git的hooks 分为客户端和服务端两种。现在提交的commit 校验icafe号,就是在服务端的hook中处理的。
这里我们只简单说下,pre-commit的客户端钩子。其它完整的可以参看git book hooks.
使用pre-commit hook
在项目根目录下的.git/hooks文件夹下有很多.sample结尾的文件,这是git提供的模板命令
去掉pre-commit.sample文件的.sample后缀,它就是一个可执行的shell文件。你可以在里面写上eslint 的校验命令,在commit之前校验代码的格式和质量。
在pre-commit文件里写入(替换掉原有的shell脚本)
echo "pre-commite 执行"
手动提交一次commit 信息,会发现打印了这句话。
至此,git hook 就了解完毕。你可以在pre-commit 里面写上eslint 命令,校验代码格式(一般我们会联合lint-staged包,只校验修改了的文件)。
2. husky 的诞生
clone 代码库时,git 并不会上传.git文件,所以也不会复制客户端钩子。在多人协作开发时会发现,git钩子并没用啥作用。
husky 的诞生是让git hook 的使用变的更加简单,对于协作项目也更加友好。ps:对于monorepo(单代码库), husky有点小问题,所以yyx 复刻了一个yorkie
3.husky@4
- 安装
npm install husky@4 -D
注意,npm的脚本有可能在一些版本失效(笔者的window在8.1的版本中就失效了),可以尝试使用yarn 或者 pnpm
- 使用
// package.json
"husky": {
"hooks": {
"pre-commit": "npm test"
}
}
- 原理
husky@4会在你的.git/hooks, 写入所有的hooks脚本,里面的命令都是执行husky.sh。
husky.sh里面的脚本,就是获取你在package.json里面配置的husky.hooks 里面的键值对。如果当前脚本名和”键”对应上,就执行后续”值”的命令。所以每次的git操作,都会触发所有的hook脚本。
- npm hook
husky 是如何做到在安装的时候,去修改.git文件的? npm-hook
官方文档中指出,在script脚本添加时,会默认添加prexxx(前置)或者postxxx(后置),意味着,你在执行install的时候,会先执行preinstall,再执行install, 最后执行postinstall。
// package.json
{
"scripts": {
"precompress": "{{ executes BEFORE the `compress` script }}",
"compress": "{{ run command to compress files }}",
"postcompress": "{{ executes AFTER `compress` script }}"
}
}
husky就是在包中添加了脚本install, 当你install包的时候,会去执行脚本husky.sh,写入自己的脚本文件到.git中。
注:这其实是很危险的一件事,你install的时候,我可以在你不知情的情况下执行一些脚本。
在npm8+的版本中,对于install的前置或者后置脚本,移除了输出。所以当你写一个简单的echo 脚本时,可能并没有达到你的预期,这并不是你的问题。你可以切换到低版本尝试,或者换一个写入文件的脚本执行。
4. husky@7
husky在6版本之后,做了破坏性的升级。因为最新版是7,所以这里我会以7的版本作为说明。
- 安装
npm install husky@7 -D
- 使用
npx husky install // 安装hooks, 这里需要手动启用
npm set-script prepare "husky install" // 设置npm hook prepare, 多人协作开发
npx husky add .husky/pre-commit "npm test" // 添加hooks 脚本
- 原理
在之前我们了解到,husky4的原理是添加所有的git hook脚本。而且如果你已经有了某个脚本,他是不会覆盖掉的,也造成了部分代码库,在其它同学上好使,在你那就不好使的情况。
在git 2.9之后,git 添加了一个配置功能,core.hooksPath, 可以指定hooks目录不在使用.git/hooks/。
所以这就是为什么必须要设置npm 脚本 prepare: “husky install” 的缘故。prepare 会在npm install 无参数的情况下运行。这样可以在第一次下载代码库的时候,进行husky 脚本的同步。
husky install 命令 会创建.husky目录,并且执行 git config –local core.hooksPath .husky, 修改hooks目录。
husky add 这条命令就是添加一个hook的脚本,写入了一个pre-commit 的文件,并且赋予了可执行权限。
需要注意的是,””文件目录里面有一个.gitignore文件。会忽略整个”“ 文件目录上传。所以必须要在项目脚本里面添加**prepare:”husky install”**脚本,用于同步其它同学的core.hooksPath 配置。这样才能生效。
6. 总结
husky 主要就是运用了git hook去进行拦截,利用npm hook去安装git hook脚本。实际上我们完全可以手动去完成这些步骤
git config core.hooksPath .myhooks // 设置hooks 目录
// mac 用户
mkdir .myhooks // 创建自定义hooks目录
touch .myhooks/pre-commit // 创建hook 脚本
echo "hello my hooks" >> .myhooks/pre-commit // 写入脚本内容
chomd +x .myhooks/pre-commit // 添加可执行权限
// 对于win用户, 手动创建.myhooks 目录 和pre-commit 文件,并且写入下方内容
#!/bin/sh
echo "hello my hooks"
// end
至此,自定义的hook就完成了,你会在git commit 的时候触发 pre-commit 脚本,也就是打印"hello my hooks"
在多人协作中,建议添加prepare脚本去执行git config.hooksPath .myhooks。这样可以保证所有开发者都是用的同一个hook脚本。