1. Git Hooks 简介
Git hooks 是 Git 提供的一种机制,允许我们在执行某些 Git 操作(如 commit、push)前后自动运行脚本。它是一种轻量级的自动化手段,虽然不如 Jenkins、Concourse 这类 CI/CD 工具强大,但在本地或服务端做一些简单校验、自动处理时非常实用。
本文将介绍 Git hooks 的基本概念、分类、管理方式,并通过两个示例演示如何创建本地和远程 Git hooks。
2. Git Hooks 类型与作用
Git hooks 分为两类:客户端钩子(client-side) 和 服务端钩子(server-side)。
- 客户端钩子:在本地仓库操作时触发,例如 commit、merge、rebase、checkout 等。
- 服务端钩子:在远程仓库收到 push 请求时触发,例如 pre-receive、update、post-receive 等。
2.1 客户端钩子
以下是一些常见的客户端钩子及其触发时机:
钩子名称 | 触发时机 |
---|---|
pre-commit | 提交前,用于代码检查、格式化等 |
prepare-commit-msg | 提交信息生成前 |
commit-msg | 提交信息生成后 |
post-commit | 提交完成后 |
pre-push | push 操作前 |
post-checkout | checkout 或 clone 后 |
还有一些较少用到的钩子,如 pre-rebase、post-rewrite、pre-auto-gc 等。
2.2 服务端钩子
服务端钩子主要在远程仓库收到 push 操作时触发:
钩子名称 | 触发时机 |
---|---|
pre-receive | 接收推送前,用于拒绝某些提交 |
update | 每个 ref 更新前调用一次 |
post-receive | 所有 ref 更新完成后,常用于部署 |
post-update | 推送完成后触发 |
这些钩子可以用来做权限控制、部署、通知等操作。
3. Git Hooks 的管理
Git hooks 存放在每个仓库的 .git/hooks/
目录下,如下是默认的几个 .sample
示例文件:
$ ls -1 .git/hooks/
applypatch-msg.sample
commit-msg.sample
fsmonitor-watchman.sample
post-update.sample
pre-applypatch.sample
pre-commit.sample
pre-merge-commit.sample
prepare-commit-msg.sample
pre-push.sample
pre-rebase.sample
pre-receive.sample
push-to-checkout.sample
update.sample
3.1 钩子的参数与环境变量
部分钩子可以通过标准输入(stdin)接收参数,例如 post-rewrite
可以根据输入判断是 commit --amend
还是 rebase
。
另外,一些钩子会设置环境变量,如 GIT_EDITOR
、GIT_COMMIT
等,用于传递上下文信息。
3.2 钩子的执行机制
- 钩子文件必须可执行:
chmod +x .git/hooks/hook-name
- 返回值决定 Git 操作是否继续:
- 返回 0 表示成功,继续执行 Git 操作
- 返回非 0 表示失败,Git 操作中止
因此,钩子文件应作为主入口,调用其他脚本并统一返回状态码。
3.3 创建或启用钩子
步骤如下:
- 在
.git/hooks/
下创建文件,文件名即为钩子名称(如pre-commit
) - 添加 shebang 行(如
#!/usr/bin/env bash
) - 编写脚本逻辑
- 执行
chmod +x
使其可执行
也可以复制 .sample
文件并重命名为钩子名。
4. 示例钩子
4.1 客户端钩子:pre-commit
这是一个 pre-commit
钩子示例,用于在提交前运行测试,若测试失败则询问是否继续提交:
#!/usr/bin/env bash
exec < /dev/tty
npm test
failed=$?
if [ $failed ]; then
while true; do
read -p 'Continue with failing tests [Yn]: ' yn
case $yn in
[Yy]* ) exit 0;;
[Nn]* ) exit 1;;
* ) echo 'Y or N';;
esac
done
fi
✅ 要点:
- 使用
exec < /dev/tty
保证能读取用户输入 npm test
执行测试- 若失败,进入交互循环,用户选择 Y/N 决定是否继续提交
4.2 服务端钩子:post-receive
这是一个 post-receive
钩子示例,在收到超过 4 个 refs 的 push 后触发部署任务:
#!/usr/bin/env bash
refs=$(cat | wc --lines)
if [ $refs -gt 4 ]; then
fly --target=node trigger-job --job nodetasks/deploy 2>&1 >/dev/null &
disown
echo 'deployed'
else
echo 'not deployed'
fi
✅ 要点:
cat | wc --lines
统计收到的 refs 数量- 使用
&
后台执行,避免阻塞客户端 - 使用
disown
防止子进程被挂起 - 使用重定向
2>&1 >/dev/null
隐藏输出
4.3 触发钩子测试
在本地仓库中模拟提交和推送:
# 创建文件
$ echo $(date) | tee --append file{1..5} >/dev/null
$ git add file{1..5}
# 提交触发 pre-commit
$ git commit --all --message 'upDate'
# 添加远程仓库
$ git remote add origin https://gerganov.com/repository
# 推送触发 post-receive
$ git push --all
输出结果中会显示 deployed
,说明钩子成功执行。
5. 总结
Git hooks 是一种轻量但功能强大的机制,适用于在 Git 操作前后执行自动化任务。
✅ 优势:
- 无需复杂配置,脚本即可生效
- 支持客户端与服务端双侧操作
- 可用于代码检查、测试、部署、权限控制等场景
⚠️ 注意:
- 钩子不会随 Git 仓库一同提交,需要手动部署
- 服务端钩子可能影响推送性能,建议异步执行
- 不要将敏感信息写入钩子文件中
合理使用 Git hooks,可以有效提升开发效率与代码质量。