Git钩子配置教程:实现自动部署的实战指南
结论:使用post-receive钩子实现自动部署 直接说结论:用 post-receive 钩子配合 GIT_WORK_TREE 环境变量,是目前最稳妥的自动部署方案。至于 post-update 或者试图在裸仓库里直接执行 checkout 的操作,建议你碰都别碰——它们不仅会失败,而且常常不给
结论:使用post-receive钩子实现自动部署
直接说结论:用 post-receive 钩子配合 GIT_WORK_TREE 环境变量,是目前最稳妥的自动部署方案。至于 post-update 或者试图在裸仓库里直接执行 checkout 的操作,建议你碰都别碰——它们不仅会失败,而且常常不给你明确的错误提示,排查起来才叫一个头疼。

为什么必须用post-receive而不是post-update
核心原因在于裸仓库(bare repo)的特性:它没有工作目录。当你使用 post-update 钩子时,Git 命令默认的执行环境仍然在 .git 目录内部,此时如果执行 git checkout,就会立刻收到一个经典的错误:fatal: this operation must be run in a work tree。
而 post-receive 钩子则不同,它是唯一一个在服务器接收完推送数据后、能够安全地通过 --work-tree 和 --git-dir 参数来指定路径的钩子。这为后续的检出操作铺平了道路。
- 信息获取方式:
post-receive通过读取标准输入(stdin)来获取 ref 的更新信息(例如refs/heads/main),这种方式非常适合用来做分支判断,实现按分支部署。 - 执行时机:
post-update虽然也能接收到参数,但此时 Git 的内部对象写入已经完成,一些关键的环境变量可能并不可靠。 - 一个常见的坑:网上很多互相抄来抄去的教程还在推荐
post-update,但实际上,尤其是在 Git 2.30 及以后的版本中,这套方案大概率会静默失败,让你查无可查。
post-receive钩子脚本的正确写法
写钩子脚本的关键,从来不是“能不能跑起来”,而是“权限对不对、路径存不存在、分支认不认”。下面是一个经过验证的最小可用模板,你可以基于它来修改:
#!/bin/sh
# 必须 unset GIT_DIR,否则后续 git 命令会误以为还在裸仓库目录下
unset GIT_DIR
# 指定部署目录(必须提前创建,且属主为运行 git 的用户,例如 git:git)
DEPLOY_PATH="/var/www/myapp"
BRANCH="main"
# 检查部署目录是否存在,避免静默失败
if [ ! -d "$DEPLOY_PATH" ]; then
echo "ERROR: $DEPLOY_PATH does not exist"
exit 1
fi
# 切换到部署目录并强制检出指定分支
cd "$DEPLOY_PATH" || exit 1
git --git-dir="/repo/myapp.git" --work-tree="$DEPLOY_PATH" checkout -f "$BRANCH" 2>&1
# 修复权限(尤其当 web 服务用户不是 git 时)
chown -R www-data:www-data "$DEPLOY_PATH"
使用这个模板时,有几个细节必须注意:
--git-dir参数必须指向裸仓库的绝对路径(比如/repo/myapp.git),使用相对路径大概率会出错。checkout -f是强制检出,它会丢弃部署目录里所有未提交的改动,包括用户上传的文件。如果生产环境有这类文件,务必在部署前将其迁移走。- 如果使用 Nginx 或 Apache 作为 Web 服务器,最后的
chown步骤不能省略,否则等待你的很可能是 502 或 403 错误。
Git自动部署常见报错与解决方案
post-receive 钩子默认不输出日志,错误信息很容易被“吞掉”。在脚本里加上简单的日志输出,能帮你快速定位问题。下面是一些典型的错误场景:
- 推送失败,提示
remote: fatal: not a git repository:首先检查--git-dir的路径是否拼写错误,然后确认该路径下是否存在objects/等 Git 仓库目录。 - 推送成功,但网站页面没有更新:可以登录服务器,执行
ls -l /var/www/myapp查看文件时间戳是否变化。更直接的方法是,手动在服务器上运行一遍钩子脚本里的git checkout命令,观察是否有报错。 - 本地推送失败,提示
Permission denied (publickey):这不是钩子脚本的问题,而是 SSH 密钥配置有误。检查服务器上~git/.ssh/authorized_keys文件是否包含了你的公钥。 - 部署后网站 CSS/JS 文件 404:这通常意味着前端构建产物(如 dist 目录)没有提交到 Git 仓库,或者钩子脚本里缺少了触发构建的命令(如
npm install && npm run build),需要你根据项目情况自行添加。
说到底,配置自动部署真正的麻烦,从来不是写那几行脚本。而是每次部署前,你都得在心里默念确认三件事:裸仓库的权限对不对、部署目录的权限对不对、Web 服务用户能不能读到那些文件。这三者漏掉任何一个,都足够让你卡上大半天。
