一、从手动上传到自动化部署
传统上线流程是"本地改代码 → 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 与多环境。




