Git Hook:让Git自动帮你干活

说实话,我刚接触Git Hook的时候,觉得这玩意儿挺玄乎的。什么钩子不钩子的,听着像钓鱼工具。直到有一次,我提交代码时忘了跑测试,结果把有bug的代码推到了线上...嗯,从那以后,我就老老实实研究Hook了。

说白了,Git Hook就是一些脚本。在特定事件发生时,Git会自动执行它们。比如你提交代码前,它帮你检查代码风格;推送代码后,它自动部署到服务器。是不是很香?

钩子到底是什么?

每个Git仓库下都有个.git/hooks目录。你进去看看,里面有一堆.sample结尾的文件。这些就是钩子的模板。

# 看看你的钩子目录
ls .git/hooks/
# 输出类似:
# applypatch-msg.sample  pre-commit.sample
# commit-msg.sample      pre-push.sample
# post-update.sample     pre-rebase.sample
# ...

想启用某个钩子?把.sample去掉就行。我习惯把不需要的钩子直接删掉,只保留要用的,看着清爽。

核心要点:钩子本质上是可执行的脚本文件。可以用Shell、Python、Ruby等任何语言写。只要它能运行,Git就认。

客户端钩子:管好你自己

客户端钩子在你自己的机器上运行。别人推不推送代码,跟你没关系。你只管管好自己的提交。

pre-commit:提交前的守门员

这个钩子我最常用。每次git commit之前,它都会跑一遍。如果返回非零值,提交就失败。

#!/bin/sh
# .git/hooks/pre-commit
# 检查是否有调试代码

if grep -rn "console.log\|debugger\|TODO" --include="*.js" .; then
  echo "❌ 发现调试代码或待办事项,请清理后再提交!"
  exit 1
fi

echo "✅ 代码检查通过"
exit 0

我曾经在一个项目里,同事把console.log带到了生产环境。页面一打开,控制台全是调试信息...从那以后,我就给团队加了这个钩子。

commit-msg:规范你的提交信息

提交信息乱七八糟?这个钩子帮你治。

#!/bin/sh
# .git/hooks/commit-msg
# 检查提交信息格式:type(scope): description

commit_msg=$(cat "$1")
pattern="^(feat|fix|docs|style|refactor|test|chore)\(.*\): .{1,50}$"

if ! echo "$commit_msg" | grep -qE "$pattern"; then
  echo "❌ 提交信息格式不对!"
  echo "正确格式:type(scope): description"
  echo "例如:feat(user): 添加登录功能"
  exit 1
fi

我的建议:commit-msg钩子配合Conventional Commits规范,团队协作会顺畅很多。你想想看,看日志的时候一目了然,多舒服。

pre-push:推送前的最后防线

这个钩子在git push时触发。我一般用它来跑测试。

#!/bin/sh
# .git/hooks/pre-push

echo "🏃 运行测试..."
npm test

if [ $? -ne 0 ]; then
  echo "❌ 测试失败,推送已阻止"
  exit 1
fi

服务端钩子:团队协作的守门人

服务端钩子跑在远程仓库上。比如GitHub、GitLab或者你自己搭的Git服务器。它管的是整个团队的代码质量。

钩子名称 触发时机 典型用途
pre-receive 服务端收到推送时 检查推送权限、代码规范
update 每个分支更新时 分支保护、强制代码审查
post-receive 推送完成后 自动部署、通知团队

我见过一个团队用pre-receive钩子做代码审查。没通过Review的代码,直接拒绝推送。虽然严格了点,但代码质量确实上去了。

常用钩子示例:实战出真知

1. 代码格式化钩子

#!/bin/sh
# pre-commit: 自动格式化代码

echo "🎨 格式化代码..."
npx prettier --write "src/**/*.{js,jsx,ts,tsx}"

# 把格式化后的文件加入暂存区
git add -u

2. 分支命名检查

#!/bin/sh
# pre-push: 检查分支命名

branch=$(git rev-parse --abbrev-ref HEAD)

if [[ ! "$branch" =~ ^(feature|bugfix|hotfix)/[a-z0-9-]+$ ]]; then
  echo "❌ 分支命名不规范"
  echo "正确格式:feature/xxx 或 bugfix/xxx 或 hotfix/xxx"
  exit 1
fi

注意:钩子脚本要设置可执行权限。我经常看到有人配好了钩子,但忘了chmod +x,结果钩子不生效。排查了半天...

自动化部署:从提交到上线

这才是钩子的高光时刻。用post-receive钩子,可以实现推送即部署。

#!/bin/sh
# 服务端 post-receive 钩子
# 实现自动部署

# 部署目录
DEPLOY_DIR="/var/www/myapp"

# 只处理主分支
while read oldrev newrev refname
do
  if [ "$refname" = "refs/heads/main" ]; then
    echo "🚀 开始部署到生产环境..."
    
    # 切换到部署目录
    cd $DEPLOY_DIR
    
    # 拉取最新代码
    git pull origin main
    
    # 安装依赖
    npm install --production
    
    # 构建项目
    npm run build
    
    # 重启服务
    pm2 restart app
    
    echo "✅ 部署完成!"
  fi
done

我有个小项目就是这么搞的。本地改完代码,git push一下,服务器自动更新。省去了手动上传的麻烦。不过要注意,生产环境慎用自动部署,最好加个手动确认步骤。

知识体系总览

下面这张图,把Git Hook的核心脉络理清楚了。你一看就明白。

Git Hook 知识体系 Git Hook 客户端钩子 服务端钩子 pre-commit commit-msg pre-push pre-receive update post-receive 代码检查 · 格式化 · 测试 权限控制 · 自动部署

避坑指南

玩钩子这些年,我踩过不少坑。分享几个给你:

  • 钩子不生效?检查文件权限。我经常忘了chmod +x,钩子文件没执行权限,Git理都不理你。
  • 团队怎么共享钩子?.git/hooks目录不会被推送。我习惯在项目根目录建个hooks文件夹,写个脚本自动复制到.git/hooks
  • 钩子执行太慢?别在钩子里跑全量测试。我一般只跑改动文件相关的测试,或者用lint-staged只检查暂存区的文件。
  • 想跳过钩子?--no-verify参数。但别滥用,我只有在紧急修复线上bug时才用。

小技巧:husky这个工具管理钩子。它能把钩子配置写在package.json里,团队共享特别方便。我个人项目基本都用它。

Git Hook这东西,说白了就是让Git在关键时刻帮你做点事。用好了,能省不少心。你想想看,每次提交都自动检查代码、跑测试、格式化,多省事。别怕配置麻烦,一次配置,长期受益。

公众号:蓝海资料掘金营,微信deep3321