推荐学习:《Git学习教程》
Git 除了版本控制,还有一些其他的高级功能,其中之一就是Git Hooks,明面意思就是钩子,可以类比于钩子函数。简单说就是Hook会在做某些事情的前后被钩子钩走去一些额外事情,那么这些额外事情我们可以用作于检查、测试和部署等操作。 在 Git 中有许多的事件(commit、push 等等),每个事件也是对应了有不同的钩子的(如 commit 前,commit 后),那么我们就可以在这些钩子这里配置一些自己需要执行的操作来实现各种各样的需求。
Git Hooks 介绍
Git hooks 是 Git 在事件之前或之后执行的脚本, 用于控制 git 工作的流程。Git hooks 脚本对于我们提交code review
之前识别一些简单的问题很有用。 我们在每次提交代码时都会触发这些 hooks,以自动指出代码中的问题,例如缺少分号,尾随空白和调试语句。通过在code review
之前指出这些问题,代码审阅者可以专注于代码结构和功能的更改,而不需要浪费时间来审查这些格式问题。 Git hooks 分为客户端钩子和服务端钩子。客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 客户端钩子:pre-commit
、prepare-commit-msg
、commit-msg
、post-commit
等,主要用于控制客户端 git 的提交和合并这样的操作。 服务端钩子:pre-receive
、post-receive
、update
,主要在服务端接收提交对象时、推送到服务器之前调用。
Git hooks 如何工作
Git Hooks 就是在.git/hooks
文件下,保存了一些 shell 脚本,然后在对应的钩子中执行这些脚本就行了。比如下图中,这是一个还没有配置 Git Hooks 的仓库,默认会有很.sample结尾的文件,这些都是示例文件 例如打开pre-commit.sample
文件看一下其中的内容,意思是一个示例钩子脚本,用于验证将要提交的内容,由没有参数的“git commit”调用,如果钩子想要停止提交,那么它应该在发出适当的消息后以非零状态退出。这个脚本默认是不生效的,如果要生效,把文件名改为pre-commit
即可。pre-commit
这个钩子是在git commit
命令执行之前触发。 Git 支持的所有钩子见下表(加粗的为常用钩子):
自定义使用方法
1. 添加命名相同的脚本文件
任何正确命名的可执行脚本都可以正常使用 ,也可以用Ruby或Python,或其他脚本语言。如下我们编写一个与prepare-commit-msg相同命名的python脚本即可,注意第一行改成了python解释器的路径。
#!/usr/bin/env pythonimport sys, oscommit_msg_filepath = sys.argv[1]with open(commit_msg_filepath, "w") as f: f.write("# Please include a useful commit message!")
此外,这里用sys.argv[1]
而不是$1来获取第一个参数。这个特性非常强大,因为你可以用任何你喜欢的语言来编写Git钩子。
2. 直接修改sample文件
使用shell 这里尝试写一个简单的钩子,安装一个prepare-commit-msg钩子。去掉脚本的.sample拓展名,在文件中加上下面这两行:
#!/bin/shecho "# Please include a useful commit message!" > $1
接下来你每次运行git commit时,你会看到默认的提交信息都被替换了。 内置的样例脚本是非常有用的参考资料,因为每个钩子传入的参数都有非常详细的说明(不同钩子不一样)。
3. 链接自定义文件
因为hook文件其实就是个脚本文件,我们可以写一个脚本文件到项目被git管理的任意目录里即可,只要在.git/hooks/里的默认脚本文件中,执行我们外部的这个文件即可。
自定义脚本文件:项目根目录/githooks/commit-msg-impl.py
#!/usr/bin/env pythonimport sys, os, refrom subprocess import check_output# 收集参数,第一个参数是commit的信息的文件commit_msg_filepath = sys.argv[1]# 打开commit提交消息的文件,检测消息是否以指定格式开头的,不是则异常退出,终止这次commit消息的提交with open(commit_msg_filepath, "r") as f: content = f.read() if not content.startswith("xxxx"): print "commit-msg: ERROR! The commit message must start with xxxx" sys.exit(1)- 默认hooks文件:.git/hooks/commit-msg#!/bin/bashGIT_ROOT="$(git rev-parse --show-toplevel)"FILE_NAME=$GIT_ROOT/githooks/commit-msg-impl.pyif [ -f "$FILE_NAME" ]; then source $FILE_NAMEfi
Husky 配置
从上面的介绍中,我们知道 Git Hook 保存在 .git 文件夹中,Git 是一个多人协作工具,那按理说 Git 仓库中的所有文件都应该被跟踪并且上传至远程仓库的。但有个例外,.git文件夹不会,这就导致一个问题,我们在本地配置好 Git Hook 后,怎么分享给其他小伙伴儿呢?这时候,就轮到 Husky 出场了。 Husky 的原理是让我们在项目根目录中写一个配置文件,然后在安装 Husky的时候把配置文件和 Git Hook 关联起来,这样我们就能在团队中使用 Git Hook 了。
第一步
使用 npm 初始化你的项目(如果项目已有 package.json,请跳至第二步)
npm init -y
第二步
安装 Husky
// 注意 Node.js 版本要 >=10npm install husky -D
第三步
书写配置文件,4.2.5 版本的 Husky 共支持以下几种格式的配置文件:
.huskyrc.huskyrc.json.huskyrc.yaml.huskyrc.yml.huskyrc.jshusky.config.js 个人习惯,这里我采用的是.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 注意事项
Husky 让我们可以很方便的配置 Git Hooks,同时,也提供了一些实用方便的小技巧以及一些我们需要注意的点
不支持的钩子
Husky 不支持服务端 Git 的钩子:
pre-receiveupdatepost-receive 跳过所有钩子 有时你可能不想运行钩子,那么可以像下面这样跳过:HUSKY_SKIP_HOOKS=1 git rebase ...
禁用自动安装
如果你不想 Husky 为你自动安装钩子(比如 clone 了一个第三方的库,想要自己开发时),可以这样做:
HUSKY_SKIP_INSTALL=1 npm install
推荐学习:《Git教程》
以上就是深入了解Git Hooks的使用的详细内容,更多请关注php中文网其它相关文章!