介绍
Git 挂钩是在 Git 生命周期中的特定点自动运行的可执行脚本。虽然许多开发人员仅将它们与代码格式化和 linting 联系起来,但它们的潜力远远超出了工作流程自动化、项目管理和团队协作。本文探讨了如何利用 Git hook 来实现全面的自动化策略。
了解 Git Hook
Git 挂钩驻留在每个存储库的 .git/hooks/ 目录中。它们是用任何语言(bash、Python、Node.js 或 Ruby)编写的标准可执行脚本。挂钩分为两类:在开发人员计算机上运行的客户端挂钩(预提交、预推送、提交消息)和在远程存储库上执行的服务器端挂钩(预接收、更新、后接收)。
钩子生命周期按时间顺序跟随 Git 操作。在提交期间,挂钩按以下顺序执行:pre-commit → commit-msg → post-commit。对于推送,顺序为 pre-push(客户端)→ pre-receive → update → post-receive(服务器)。
与 Husky 设置 Hook
通过将脚本放置在 .git/hooks/ 中来手动管理挂钩对于团队来说是不切实际的,因为 Git 不跟踪该目录。 Husky 通过允许在存储库中配置挂钩并在团队中共享来解决这个问题。
Husky v9+ 的安装非常简单:
npx husky init
这将创建一个 .husky/ 目录,其中挂钩脚本是纯文本文件:
# .husky/pre-commit
npx lint-staged
对于 CI 环境,可以通过设置 HUSKY=0 来跳过钩子:
HUSKY=0 git push
集成 lint-staged
Lint-staged 仅在暂存文件上运行 linter,从而保持快速的预提交检查:
{
"lint-staged": {
"*.{ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{css,scss}": ["stylelint --fix", "prettier --write"]
}
}
预提交挂钩:第一道防线
预提交挂钩在每次提交之前执行,非常适合快速、本地化检查。
| 检查类型 | 工具 | 目的 |
|---|---|---|
| 绒毛 | ESLint、stylelint | 执行代码风格标准 |
| 格式化 | 更漂亮,dprint | 一致地自动格式化代码 |
| 类型检查 | 打字稿 --noEmit | 及早发现类型错误 |
| 秘密侦查 | Secretlint,松露Hog | 防止凭证泄露 |
| 文件验证 | 自定义脚本 | 阻止大文件或 TODO 提交 |
全面的预提交配置:
# .husky/pre-commit
npx lint-staged
npx tsc --noEmit
npx secretlint "**/*"
性能至关重要 - 预提交挂钩应在五秒内完成,以避免中断开发流程。
预推挂钩:CI 安全网
预推送挂钩在代码到达远程存储库之前运行,这使得它们非常适合长时间运行的验证:
# .husky/pre-push
npm test
npm run build
npm audit
分支命名验证确保整个团队的一致性:
#!/bin/sh
branch=$(git rev-parse --abbrev-ref HEAD)
if ! echo "$branch" | grep -qE '^(feature|bugfix|hotfix)/[A-Z]+-[0-9]+-'; then
echo "Error: Branch name must match feature/ABC-123-description"
exit 1
fi
使用 commitlint 进行提交消息挂钩
强制执行传统的提交消息可确保一致的、可解析的历史记录。将 commitlint 与 Husky 一起使用:
# .husky/commit-msg
npx --no -- commitlint --edit $1
在 commitlint.config.js 中配置 commitlint:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'subject-max-length': [2, 'always', 50],
'body-max-line-length': [2, 'always', 72],
},
};
有效的提交消息遵循 <type>(<scope>): <description> 格式:
feat(auth): implement OAuth 2.0 refresh token rotation
fix(api): handle null pointer in user deserialization
docs(readme): update installation instructions
提交后和合并后挂钩
合并后挂钩对于依赖管理特别有用。当锁定文件更改时自动安装更新的依赖项:
# .husky/post-merge
changed=$(git diff HEAD~1 --name-only)
if echo "$changed" | grep -q "pnpm-lock.yaml"; then
pnpm install
fi
CI 等效策略
最稳健的模式可确保钩子和 CI 运行相同的检查。提取两个环境调用的共享脚本:
#!/bin/sh
# scripts/validate.sh - called by both hooks and CI
npm run lint
npm run typecheck
npm test
本地挂钩应尽可能发出警告或自动修复,而 CI 则严格执行。这创建了一个安全网:开发人员在推送之前发现问题,而 CI 捕获任何漏掉的东西。
结论
Git hooks 是一个强大的自动化层,其功能远远超出了代码格式化的范围。将 Husky 与 lint-staged 结合起来为大多数项目提供了推荐的基线。预推送钩子在代码到达 CI 之前添加了一个安全网,并且 commitlint 确保了干净、可解析的提交历史记录。最终目标是提供无缝的开发人员体验,其中自动化处理重复检查,使团队能够专注于逻辑和设计。

