Git Webhook自动部署实战:post-receive钩子与一键回滚方案


一、从手动上传到自动化部署

传统上线流程是"本地改代码 → FTP/SFTP 上传 → 服务器手工重启",步骤多、易出错、难以回滚。Git 时代更优雅的方式是:服务器上维护一个 bare 仓库,本地 git push 时通过钩子自动把代码同步到 Web 目录,甚至触发构建与重启。再配合 Webhook 还能联动 CI(如 GitHub Actions、Gitee/Gitea 的 Webhook),实现"push 即上线"。这套流程让部署变成一次简单的 git push,省时且可追溯。

二、服务器端:初始化 bare 仓库

先在服务器建一个专门放 git 仓库的目录,并用 --bare 初始化(bare 仓库没有工作区,只存放版本数据,适合作为中央仓库):

# 建目录并初始化裸仓库
sudo mkdir -p /var/git/site.git
cd /var/git/site.git
sudo git init --bare

# 创建 Web 站点目录
sudo mkdir -p /var/www/site

裸仓库的 hooks 目录位于 /var/git/site.git/hooks/,这是接下来自动部署的触发点。

三、post-receive 钩子:push 即部署

在服务器裸仓库的 hooks 目录创建 post-receive 脚本,git push 完成后自动执行:

#!/bin/bash
# /var/git/site.git/hooks/post-receive
TARGET=/var/www/site
export GIT_WORK_TREE=$TARGET

# 1. 检出到 Web 目录
git --work-tree=$TARGET checkout -f

# 2. 处理依赖/构建(按项目类型选择,注释掉不需要的)
# cd $TARGET && composer install --no-dev --optimize-autoloader
# cd $TARGET && npm install --production && npm run build

# 3. 权限修正(让 Web 用户可读)
chown -R www-data:www-data $TARGET
chmod -R 755 $TARGET

# 4. 记录部署日志
echo "$(date '+%F %T') deployed commit $(git rev-parse --short HEAD)" >> /var/log/git-deploy.log
sudo chmod +x /var/git/site.git/hooks/post-receive

钩子里的 checkout -f 会把 push 进来的最新代码强制检出到 TARGET。构建与依赖安装(composer/npm)放在钩子里,push 后自动完成,保证线上和仓库永远一致。如果站点目录里的配置文件(如数据库密码)不能进仓库,注意用 .gitignore 排除并在服务器单独维护,避免钩子覆盖。

四、本地推送到服务器

本地仓库加 remote 后即可一键上线:

# 本地执行(假设服务器 IP 为 1.2.3.4)
git remote add deploy root@1.2.3.4:/var/git/site.git
git push deploy master

第一次 push 若提示主机指纹确认,用 ssh -o StrictHostKeyChecking=accept-new root@1.2.3.4 先连一次。SSH 免密沿用之前讲过的密钥登录方案。push 完成后查看部署日志即可确认:cat /var/log/git-deploy.log。

也可以限制服务器上只允许 deploy 专用用户、用非标准端口、甚至配 receive.denyCurrentBranch 等安全策略。注意不要把服务器 SSH 密钥提交进仓库或公网。

五、Webhook:联动 CI 与外部服务

如果项目用 GitHub/Gitee/GitLab,服务器还可主动"订阅"推送事件:在仓库设置里添加 Webhook,指向服务器的接收脚本,服务器收到 POST 后执行部署。这样一个简单的 PHP 接收脚本示例:

<?php
// /var/www/webhook/deploy.php 收到 Webhook POST 后执行
$secret = 'your-shared-secret';          // 与仓库 Webhook 配置一致
$payload = file_get_contents('php://input');
$sign = 'sha256=' . hash_hmac('sha256', $payload, $secret);
if (!hash_equals($sign, $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '')) {
    http_response_code(403); exit('forbidden');
}
// 触发部署(后台执行,避免阻塞响应)
exec('cd /var/www/site && git pull -q origin master >> /var/log/webhook.log 2>&1 &');
echo 'ok';

上面用 HMAC 签名校验请求来自仓库平台,防止伪造。生产建议把 Webhook 接收脚本放在内网或加 IP 白名单,部署动作交给有权限的专用用户,并限制其只对站点目录有写权限。

六、回滚:出问题怎么撤销

自动化部署最大的隐忧是"推错代码直接上线"。回滚方案提前准备好:

# 方式1:git 回滚后重新推送(适合已 push 的错误提交)
git revert HEAD --no-edit     # 本地生成反向提交
git push deploy master        # 触发钩子自动部署回退版本

# 方式2:直接回退远程分支(谨慎,非协作场景可用)
git push deploy master~1:master

# 方式3:服务器端快速回退到上一提交
cd /var/git/site.git
git --work-tree=/var/www/site checkout -f HEAD~1

更稳的是"发布前打 tag":每次上线前 git tag release-$(date +%F),出问题时 checkout -f 指定tag 即可精确回退到某个发布点。回滚后再把修复 commit push 上去恢复正常流程。

七、避坑清单与安全建议

  • 配置不进仓库:.env、数据库密码、密钥一律 gitignore,服务器单独维护。
  • 钩子权限最小化:deploy 用户只给站点与仓库目录写权限,别用 root 跑钩子。
  • 防止钩子覆盖运行中的服务:发布需要重启服务的(如 systemd 应用),把 systemctl restart 也放进钩子并加日志。
  • Webhook 必验签:用 HMAC 或固定 token,禁止无鉴权触发。
  • 构建失败要能发现:钩子里构建命令失败时用 set -e 终止,避免"半成品上线"。
  • 备份先行:上线前先按前面文章讲过的 rsync 备份当前线上目录,回滚兜底。

写在最后

Git 自动部署把"上传、同步、重启、回滚"压缩成一次 push,是现代开发工作流里性价比极高的一环。核心就三块:服务器 bare 仓库 + post-receive 钩子完成自动检出;本地 remote 一键推送;需要联动平台时加带验签的 Webhook。配合 tag 回滚、配置不进仓库、权限最小化三条纪律,你就能享受"push 即上线"的顺畅,又不必担心误操作把站点搞挂。先从单机裸仓库开始,跑顺了再谈 CI 与多环境。


手机扫码阅读

微信或手机浏览器扫一扫,随时随地随心阅读与分享

WireGuard加密隧道组网实战:密钥配置、全隧道分流与排错指南

PHP-FPM性能调优实战:进程模式、max_children计算与慢日志定位

评 论
更换验证码