Git Hooks 完整指南
约 1493 字大约 5 分钟
2026-04-10
Git Hooks 是 Git 提供的脚本机制,允许在特定事件发生时自动执行自定义代码。它们是提升代码质量、规范工作流的强大工具。
什么是 Git Hooks
Git Hooks 是存放在 .git/hooks/ 目录下的脚本文件,会在特定的 Git 操作(如提交、合并、推送等)前后自动触发执行。
核心特性
- 自动化:减少手动操作,提升效率
- 强制性:通过脚本强制执行规范
- 灵活性:支持任何可执行脚本(Bash、Python、Node.js 等)
- 本地性:默认只在本地仓库生效(可通过工具共享)
Hooks 执行时机
Git Hooks 按照执行时机可分为两大类:
客户端 Hooks
| Hook 名称 | 触发时机 | 典型用途 |
|---|---|---|
pre-commit | 提交信息编辑器启动前 | 代码格式化、lint 检查 |
prepare-commit-msg | 提交信息编辑器启动后,提交前 | 修改提交信息模板 |
commit-msg | 提交信息输入完成后 | 验证提交信息格式 |
post-commit | 提交完成后 | 发送通知、更新统计 |
pre-push | 推送到远程前 | 运行测试、检查分支 |
post-merge | 合并完成后 | 安装依赖、重建项目 |
pre-rebase | 变基操作前 | 检查变基安全性 |
服务端 Hooks
| Hook 名称 | 触发时机 | 典型用途 |
|---|---|---|
pre-receive | 接收推送前 | 权限检查、策略验证 |
update | 每个 ref 更新前 | 分支保护、策略执行 |
post-receive | 推送完成后 | 触发 CI/CD、发送通知 |
常见使用场景
1. 代码质量检查
#!/bin/bash
# .git/hooks/pre-commit
echo "运行代码检查..."
npm run lint
if [ $? -ne 0 ]; then
echo "❌ Lint 检查失败,提交被拒绝"
exit 1
fi
echo "✅ 检查通过"
exit 02. 提交信息规范验证
#!/bin/bash
# .git/hooks/commit-msg
commit_msg=$(cat "$1")
# 检查是否符合 Conventional Commits 规范
if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?: .+"; then
echo "❌ 提交信息格式不符合规范"
echo "格式: <type>(<scope>): <description>"
echo "例如: feat(auth): 添加用户登录功能"
exit 1
fi
exit 03. 防止提交敏感文件
#!/bin/bash
# .git/hooks/pre-commit
# 检查是否提交了包含密钥的文件
if git diff --cached --name-only | grep -qE '\.(env|key|pem|secret)$'; then
echo "❌ 检测到敏感文件,禁止提交"
git diff --cached --name-only | grep -E '\.(env|key|pem|secret)$'
exit 1
fi
exit 0全局 Git Hooks 配置
项目级别 hooks 仅对当前仓库生效。如需跨项目统一规范,可配置全局 hooks。
配置方法
# 1. 创建全局 hooks 目录
mkdir -p ~/.git-templates/hooks
# 2. 配置 Git 使用全局 hooks 目录
git config --global core.hooksPath ~/.git-templates/hooks验证配置
# 查看当前 hooks 路径配置
git config --global core.hooksPath实践案例:自动清理提交信息
本项目使用 prepare-commit-msg hook 来自动清理提交信息中的 Co-authored-by: 标记。
#!/bin/bash
# ~/.git-templates/hooks/prepare-commit-msg
# 自动移除 Co-authored-by:标记
COMMIT_MSG_FILE="$1"
COMMIT_SOURCE="$2"
# 只在非 merge、非 squash 的普通提交时清理
if [ "$COMMIT_SOURCE" != "merge" ] && [ "$COMMIT_SOURCE" != "squash" ]; then
# 移除 Co-authored-by:行
sed -i '' '/^Co-authored-by:/d' "$COMMIT_MSG_FILE"
# 清理末尾多余的空行
sed -i '' -e :a -e '/^\n*$/{$d;N;ba' -e '}' "$COMMIT_MSG_FILE"
fi设置可执行权限:
chmod +x ~/.git-templates/hooks/prepare-commit-msg共享 Git Hooks 方案
由于 .git/hooks/ 目录不会被 Git 跟踪,团队共享 hooks 有以下几种方案:
方案 1:使用 core.hooksPath
在项目根目录创建 git-hooks/ 文件夹,并在项目配置中指定路径:
# 项目级配置
git config core.hooksPath .git-hooks
# 或在 .gitconfig 中全局配置
git config --global core.hooksPath ~/.git-templates/hooks方案 2:使用 Husky(推荐前端项目)
Husky 是现代前端项目最常用的 Git Hooks 管理工具。
# 安装 Husky
npm install husky --save-dev
# 启用 Git hooks
npx husky install
# 添加 hooks
npx husky add .husky/pre-commit "npm run lint"
npx husky add .husky/commit-msg "npx --no-install commitlint --edit"方案 3:使用 lefthook
Lefthook 是更快的替代方案,支持并行执行 hooks。
# lefthook.yml
pre-commit:
parallel: true
commands:
lint:
glob: "*.{js,ts,jsx,tsx}"
run: npx eslint {staged_files}
types:
glob: "*.{js,ts,jsx,tsx}"
run: npx tsc --noEmit
commit-msg:
commands:
commitlint:
run: npx commitlint --edit {1}推荐工具生态
| 工具 | 用途 | 适用场景 |
|---|---|---|
| Husky | Git Hooks 管理 | 前端/Node.js 项目 |
| lint-staged | 对暂存文件运行 linter | 配合 Husky 使用 |
| Commitlint | 校验提交信息格式 | Conventional Commits |
| Commitizen | 交互式生成提交信息 | 规范化提交流程 |
| Lefthook | 快速并行 hooks | 大型项目/多语言项目 |
| Pre-commit | Python 生态 hooks | Python 项目 |
最佳实践
1. 保持 Hooks 快速执行
# ❌ 不好的做法:运行完整的测试套件
npm test
# ✅ 好的做法:只运行受影响文件的检查
npx eslint --cache --fix2. 提供清晰的错误信息
#!/bin/bash
# 好的错误提示
echo "❌ 提交失败:代码包含 lint 错误"
echo "请运行 'npm run lint:fix' 修复后再提交"
echo ""
echo "如需跳过检查(不推荐):git commit --no-verify"
exit 13. 允许紧急情况跳过
# 在 hooks 脚本中检查环境变量
if [ "$SKIP_HOOKS" = "true" ]; then
exit 0
fi
# 用户可通过 --no-verify 跳过
git commit --no-verify
git push --no-verify4. 文档化团队规范
在项目 README.md 或 CONTRIBUTING.md 中说明:
- 使用了哪些 hooks
- hooks 的作用
- 如何配置本地环境
- 如何临时跳过 hooks(紧急情况)
故障排查
Hooks 不生效
# 1. 检查文件是否有可执行权限
ls -la .git/hooks/pre-commit
# 2. 添加可执行权限
chmod +x .git/hooks/pre-commit
# 3. 检查 hooks 路径配置
git config core.hooksPath
# 4. 查看 Git 日志
git commit 2>&1 | head -20调试 Hooks 脚本
#!/bin/bash
# 在 hooks 脚本开头添加调试输出
set -x # 开启调试模式
exec 2>/tmp/git-hook-debug.log # 重定向输出到文件
echo "=== Debug: $(date) ==="
echo "Hook: $0"
echo "Args: $@"
echo "PWD: $(pwd)"