你好,我是小桔,是一个没有感情的代码崽。前端
今天给你们介绍一下 Git Hooks,相信 Git 你们都在用吧,Git 除了用做版本控制,还有许多高级功能,Git Hooks 就是其中之一。react
本文环境:webpack
- Git 版本:2.27.0
- Husky 版本:4.2.5
- Node.js 版本:12.16.2
作过前端的同窗对 Hook 这个东西应该很了解吧,后端也是有 Hook 这种概念的,好比 Java 的@PostConstruct
,也是一种 Hook 的体现。简单来讲,Hook 就是在执行某个事件以前或以后进行一些其余额外的操做。git
举个栗子,张三如今要吃饭,那么吃饭就是一个事件,吃饭前和吃饭后就能够称为两个钩子。如今你想让张三在吃饭前洗下手,那么咱们就能够在吃饭前这个钩子这里,设置一个洗手的动做。张三在每次吃饭前,都会检查一下这个钩子,有什么要作的,都会照作。这样,就实现了咱们的需求。github
Git 也是如此,在 Git 中也有许多的事件(commit、push 等等),每一个事件也是对应了有不一样的钩子的(如 commit 前,commit 后),那么咱们就能够在这些钩子这里配置一些本身须要执行的操做来实现各类各样的需求。web
可能初次了解 Git Hooks 的同窗会有一些疑问:这个东西到底能干吗?我之前没用过它不也同样好好的吗?我干吗要用它?shell
其实这说得很对,任何技术都是有需求采用,没有需求就别去硬塞,永远记住:技术为业务服务。可是这并不妨碍你先去了解它,毕竟,只有你先知道了这项技术能解决什么样的问题,往后当你遇到相应的问题时,你才知道该用什么技术去解决。npm
这里我给出一个真实的场景,是咱们团队在开发 Lin UI 的时候遇到的:json
咱们的 Git 仓库中包含了编译后的代码,因此每次修改了源码,都须要运行一下编译命令,而后把源码和编译后的代码一块儿提交到 Git 仓库,这个流程没什么问题。可是,人脑不是电脑,总会有疏忽的时候,常常会出现这样一种状况:修改了源码,却忘记了运行编译命令,最后只把源码提交到了 Git 仓库,致使线上仓库的源码和编译产物不一致、后端
这个问题虽然不是特别严重,但总是出现也总归很差。因此咱们就想了一个办法,再也不手动编译,把编译任务交给 CI 去作,这样就不存在这样的问题。
但事情老是没那么顺利,由于咱们在本地开发调试的时候是须要编译代码的,因此就会生成一部分编译代码,在使用 Git 时,咱们常常会使用git add .
命令,会把全部修改了的代码都提交到仓库,这显示是不行的。由于如今咱们已经把编译交给 CI 去作了,而且为了 Code Review 方便,编译代码不该该再提交到仓库了。若是每次手动去把编译代码去除,又很是麻烦,那该怎么办呢?
这种状况,就可使用 Git Hooks 帮咱们在每次提交前自动把编译代码去掉了。
PS:这个场景虽然不那么常见和通用,但确实是在开发中真实碰见的。
Git Hooks 的实现其实很是简单,就是就.git/hooks
文件下,保存了一些 shell 脚本,而后在对应的钩子中执行这些脚本就好了。好比下图中,这是一个尚未配置 Git Hooks 的仓库,默认会有不少.sample
结尾的文件,这些都是示例文件
咱们打开pre-commit.sample
文件看一下其中的内容,大体意思是说这是一个示例,作了一些格式方面的检测,这个脚本默认是不生效的,若是要生效,把文件名改成pre-commit.sample
便可
pre-commit
这个钩子是在git commit
命令执行以前触发
Git 支持的全部钩子见下表(加粗的为经常使用钩子):
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 做出反应并更新仓库中的引用时 |
|
push-to-checkout | 当`git-receive-pack 对git push 作出反应并更新仓库中的引用时,以及当推送试图更新当前被签出的分支且receive.denyCurrentBranch 配置被设置为updateInstead 时 |
|
pre-auto-gc | git gc --auto 执行前 |
|
post-rewrite | 执行git commit --amend 或git rebase 时 |
|
sendemail-validate | git send-email 执行前 |
|
fsmonitor-watchman | 配置core.fsmonitor 被设置为.git/hooks/fsmonitor-watchman 或.git/hooks/fsmonitor-watchmanv2 时 |
|
p4-pre-submit | git-p4 submit 执行前 |
能够用git-p4 submit --no-verify 绕过 |
p4-prepare-changelist | git-p4 submit 执行后,编辑器启动前 |
能够用git-p4 submit --no-verify 绕过 |
p4-changelist | git-p4 submit 执行并编辑完changelist message 后 |
能够用git-p4 submit --no-verify 绕过 |
p4-post-changelist | git-p4 submit 执行后 |
|
post-index-change | 索引被写入到read-cache.c do_write_locked_index 后 |
PS:完整钩子说明,请参考官网连接
从上面的介绍中,咱们知道 Git Hook 保存在 .git 文件夹中。不知你有没有发现这会有一个问题?可能细心的同窗已经知道了,Git 是一个多人协做工具,那按理说 Git 仓库中的全部文件都应该被跟踪而且上传至远程仓库的。可是有个例外,.git
文件夹不会,这就致使一个问题,咱们在本地配置好 Git Hook 后,怎么分享给其余小伙伴儿呢?copy 吗?那未免太 low 了,都用 Git 了,还 copy,也太不优雅了。这时候,就轮到 Husky 出场了。
Husky 是一个让配置 Git 钩子变得更简单的工具(题外话:Husky 是哈士奇的意思,我猜多是做者养了条二哈)
下面这些流行的项目都在使用 Husky,可见它确实是一个很是好用的工具:
Husky 的原理是让咱们在项目根目录中写一个配置文件,而后在安装 Husky的时候把配置文件和 Git Hook 关联起来,这样咱们就能在团队中使用 Git Hook 了。
下面开始配置 Husky
使用 npm 初始化你的项目(若是项目已有 package.json,请跳至第二步)
npm init -y
安装 Husky
// 注意 Node.js 版本要 >=10 npm install husky -D
书写配置文件,4.2.5 版本的 Husky 共支持如下几种格式的配置文件:
我的习惯,这里我采用的是.huskyrc
,在其中书写 json 格式的配置,以下:
{ "hooks": { "pre-commit": "git restore -W -S dist examples/dist" } }
是否是很简单,咱们来解读一下这个配置文件。hooks
这个对象中,key 就是钩子名,而 value 就是须要执行的命令。上面这个配置的含义就是,在每次执行 git commit
以前,都会把dist
和examples/dit
目录下的修改回滚(这两个目录就是编译产生的代码),就不用担忧误把编译后的代码提交到仓库中了。
上面咱们只写了一条命令,若是想执行两条命令怎么办呢?好比我还想在git commit
以前用 EsLint 检查一下代码质量,咱们能够像下面这样写:
{ "hooks": { "pre-commit": "git restore -W -S dist examples/dist && eslint ." } }
是的,就是这么简单。若是 EsLint 检测不经过,那么git commit
是会被阻止的,就不用担忧"垃圾代码"被提交到线上仓库了。
Husky 让咱们能够很方便的配置 Git Hooks,同时,也提供了一些实用方便的小技巧以及一些咱们须要注意的点
Husky 不支持服务端 Git 的钩子:
有时你可能不想运行钩子,那么能够像下面这样跳过:
HUSKY_SKIP_HOOKS=1 git rebase ...
若是你不想 Husky 为你自动安装钩子(好比 clone 了一个第三方的库,想要本身开发时),能够这样作:
HUSKY_SKIP_INSTALL=1 npm install
本文介绍了 Git Hooks 具体有哪些,并讲解了如何用 Husky 便捷的配置 Git Hook。下一篇文章,我会教你如何用 commitlint 结合 Husky 来规范团队的 commit 信息,若是有兴趣的话,记得必定要关注我哦!
我是小桔,欢迎关注个人微信公众号,带你了解更多先后端知识。