用途
Git Hooks 用于通过 Git 钩子自动化代码质量检查、强制执行约定,并阻止不良提交进入仓库。它适用于希望在本地提交与推送阶段就完成 lint、格式化、密钥扫描、提交信息校验等工作的开发流程。
钩子类型与用途
资料给出的钩子类型及常见用途对照:
- pre-commit:在创建提交之前触发,常见用途为 lint、格式化、密钥扫描。
- prepare-commit-msg:在默认信息生成后、编辑前触发,常见用途为添加工单 ID、模板。
- commit-msg:在用户写完提交信息后触发,常见用途为强制 Conventional Commits。
- pre-push:在推送到远端之前触发,常见用途为完整测试套件、构建检查。
- pre-rebase:在变基开始前触发,常见用途为防止对受保护分支进行变基。
- post-merge:在合并完成后触发,常见用途为重装依赖、运行迁移。
- post-checkout:在检出/切换后触发,常见用途为重新构建、清理缓存。
主要工具与配置方式
Husky v9(Node.js 项目)
安装与初始化命令:
npm install -D husky
npx husky init
初始化会创建带 pre-commit 钩子的 .husky/ 目录,并在 package.json 中添加 "prepare": "husky"。创建钩子时,每个钩子都是普通 shell 脚本,例如:
echo "npx lint-staged" > .husky/pre-commit
echo "npm test" > .husky/pre-push
echo 'npx --no -- commitlint --edit "$1"' > .husky/commit-msg
v9 与 v8 的关键差异:不再需要 source husky.sh,钩子是普通脚本;内部通过 "prepare" 脚本使用 core.hooksPath;如果克隆后钩子不运行,可执行 npm run prepare。
lint-staged 配置
JSON 配置示例:
{
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,md,yml,yaml}": "prettier --write",
"*.css": ["stylelint --fix", "prettier --write"],
"*.py": ["ruff check --fix", "ruff format"],
"*.go": ["gofmt -w", "go vet ./..."]
}
}
函数式配置(lint-staged.config.mjs)可针对改动文件范围运行命令,例如任意 TS 文件变化时对整个项目运行 tsc --noEmit、显式传入文件名、只运行相关测试(jest --findRelatedTests)。
Lefthook(现代替代方案)
安装与初始化:
npm install -D lefthook # 或: brew install lefthook
npx lefthook install
lefthook.yml 可声明 pre-commit(并行执行 lint、format、types)、commit-msg(validate)、pre-push(test)。资料列出 Lefthook 优势:YAML 配置、内置并行执行、glob 过滤、{staged_files} 变量、Go 二进制(无 Node 依赖)、原生 monorepo root: 支持。
pre-commit 框架(Python/多语言)
安装:
pip install pre-commit
pre-commit install
pre-commit install --hook-type pre-push
.pre-commit-config.yaml 可引用官方钩子仓库(trailing-whitespace、end-of-file-fixer、check-yaml、check-added-large-files、detect-private-key、check-merge-conflict)、ruff-pre-commit,以及本地钩子(如 pytest,stages: [pre-push])。常用命令:pre-commit run --all-files、pre-commit autoupdate。
自定义钩子脚本
资料提供多类自定义脚本示例:
- Conventional Commits 强制校验(commit-msg 中匹配 type(scope): description 格式,不符合则报错退出)。
- 分支命名强制(pre-push 中校验 feature/bugfix/hotfix/release/chore 前缀)。
- 密钥检测(pre-commit 扫描暂存文件的敏感模式)。
- 文件大小限制(pre-commit 阻止超过 1MB 的文件)。
- 合并冲突标记检查(pre-commit 阻止含 <<<<<<<、=======、>>>>>>> 的文件)。
- Node.js 版 commit-msg 与 Python 版 pre-commit(语法检查暂存 Python 文件)示例。
团队共享钩子
- Husky:钩子位于 .husky/,通过 "prepare": "husky" 自动安装。
- core.hooksPath:与语言无关,创建 .githooks 并 chmod +x,再执行 git config core.hooksPath .githooks;可通过 scripts 的 prepare 自动执行该配置。
- 共享 .gitconfig(开发者自愿启用):提交含 [core] hooksPath = .githooks 的 .gitconfig,开发者运行 git config --local include.path ../.gitconfig。
跳过钩子
git commit --no-verify -m "hotfix: emergency production fix"
git push --no-verify
资料说明:适用于紧急热修复、WIP 提交、钩子损坏阻塞工作;不适用于经常跳过失败测试、绕过密钥检测。
调试钩子
git config core.hooksPath # 查看当前钩子目录(空表示 .git/hooks/)
git rev-parse --git-path hooks # 解析后的路径
bash -x .husky/pre-commit # 追踪执行
chmod +x .githooks/pre-commit # 修复权限
常见问题:缺少 chmod +x、shebang 错误、nvm 未加载(钩子不 source .bashrc)、core.hooksPath 错误。nvm 修复方式为在钩子中加入 export NVM_DIR="$HOME/.nvm" && . "$NVM_DIR/nvm.sh";调试环境变量可临时加入 env > /tmp/hook-env.txt。
Monorepo 模式
- Lefthook monorepo:通过 root: packages/frontend/ 与 root: packages/backend/ 分别运行前端与后端 lint。
- lint-staged monorepo:根配置中按包路径匹配并 cd 到对应目录执行命令。
- 仅测试受影响包的 pre-push 脚本:通过 git diff --name-only @{push}.. 判断哪些包发生变化并分别运行测试。
CI/CD 钩子等价物
资料给出 GitHub Actions 工作流示例:在 push、pull_request 时运行 npm ci、eslint、prettier --check、npm test、commitlint,作为本地钩子的 CI 端安全网。
适用场景与限制
适用于需要在提交与推送阶段统一代码质量与提交规范的团队,以及使用 Node.js、Python 或多语言仓库的项目。资料未提供具体收费、价格或平台支持信息。跳过钩子(--no-verify)应仅限特定情形,不应作为常规做法。