Git 钩子实战:自动化代码检查与部署

本文深入解析 Git 钩子,指导你利用 pre-commit、post-receive 等钩子实现代码检查与自动化部署,涵盖配置步骤、常见误区与失败条件,助你提升开发效率。

Git 钩子实战:自动化代码检查与部署
封面图:ZuCDN · ZuCDN 原创

Git 钩子(Git Hooks)是 Git 在特定事件发生时自动执行的脚本,利用它们可以在提交、推送等关键节点自动运行代码检查和部署任务,从而将质量保障左移。然而,许多团队对钩子的能力边界和配置细节理解不足,导致钩子失效或误用。本文直接给出判断路径:先明确你的自动化需求对应哪个钩子事件,再编写脚本并设置执行权限,最后通过测试验证钩子是否按预期触发。下面展开细节。

确定钩子事件的判断路径

Git 钩子分为客户端钩子和服务端钩子。客户端钩子运行在开发者本地,服务端钩子运行在远程仓库。选择哪个钩子取决于你想要拦截的时机:

  • pre-commit:在提交前运行,适合执行代码风格检查、单元测试等快速校验。
  • commit-msg:在提交信息保存前运行,可校验提交信息格式。
  • pre-push:在推送前运行,适合运行更耗时的测试或构建。
  • post-receive:服务端钩子,在推送接收后运行,常用于自动部署到测试或生产环境。

判断路径:如果你的需求是阻止不合规的代码进入本地历史,选择 pre-commit;如果是阻止推送到远程,选择 pre-push;如果是触发服务器端的自动化部署,则必须使用服务端钩子 post-receive。注意,客户端钩子不会被克隆,需要额外分发。

配置钩子的操作步骤

每个 Git 仓库的钩子脚本存放在 .git/hooks 目录下,默认以 .sample 结尾。配置步骤如下:

  1. 进入 .git/hooks 目录,新建文件(例如 pre-commit),去掉 .sample 后缀。
  2. 编写脚本,使用任意可执行语言,但需确保 shebang 正确(如 #!/bin/sh)。
  3. 赋予执行权限:chmod +x pre-commit
  4. 测试钩子:执行 git commit,观察脚本是否运行。

示例:一个简单的 pre-commit 钩子,检查代码中是否包含调试语句:

#!/bin/sh
if grep -r "console.log" src/; then
  echo "Error: console.log found in src/"
  exit 1
fi
exit 0

实现自动化代码检查的钩子设计

代码检查是钩子最常见的用途。你可以让 pre-commit 钩子运行 linter(如 ESLint、RuboCop)或格式化工具(如 Prettier)。关键设计原则:

  • 钩子应快速,避免拖慢提交流程。
  • 只检查暂存区(staged)的文件,而不是整个工作区,使用 git diff --cached --name-only 获取文件列表。
  • 失败时返回非零退出码,阻止提交。

常见误区:直接运行全量检查,导致提交变慢;或者没有暂存区文件,导致误报。正确做法是限定检查范围,并允许跳过(通过 --no-verify),但需在文档中明确风险。

实现自动化部署的钩子设计

自动化部署通常使用服务端钩子 post-receive。该钩子在推送完成后运行,可以配合裸仓库和部署目录实现。基本思路:

  • 在服务器上建立裸仓库(bare repo),并设置 post-receive 钩子。
  • 钩子内执行 git --work-tree=/path/to/deploy --git-dir=/path/to/bare.git checkout -f 更新工作目录。
  • 可接着运行构建命令(如 npm install、npm run build)和重启服务。

示例 post-receive 钩子:

#!/bin/bash
TARGET="/var/www/myapp"
GIT_DIR="/home/git/myapp.git"
while read oldrev newrev ref
do
  if [ "$ref" = "refs/heads/main" ]; then
    git --work-tree=$TARGET --git-dir=$GIT_DIR checkout -f
    cd $TARGET && npm install && npm run build
    systemctl restart myapp
  fi
done

钩子的取舍与失败条件

使用钩子需要权衡:客户端钩子容易被开发者绕过(--no-verify),服务端钩子则不可绕过,但部署逻辑需谨慎编写,否则可能破坏生产环境。失败条件包括:

  • 脚本权限未设置,导致无法执行。
  • 脚本路径错误或依赖缺失。
  • 钩子中使用了交互式命令,导致挂起。
  • 服务端钩子中未正确处理分支过滤,导致所有分支都触发部署。

常见误区:依赖客户端钩子作为唯一防线,而服务端未设置保护;或者钩子脚本过于复杂,难以维护。建议将钩子脚本纳入版本控制(如使用 husky 等工具),并配合 CI 系统(如 GitHub Actions)形成多层防护。

与 CI/CD 工具的协同

Git 钩子适合轻量级、快速反馈的场景,但复杂的工作流(如多平台测试、发布)应交给 CI/CD 工具。例如,GitHub Actions 可以监听 push 事件,运行完整的流水线,而钩子只做本地预检。这种分层策略兼顾了效率与可靠性。相关实践可参考 GitHub Actions 官方文档。

参考资料

延伸阅读