EP118. “裸仓库与 post-receive Hook 实现 git push 部署”
🔒 登录后可标记已读把线上服务器配置成一个可以被 git push 的目标:在公开可访问的网站目录之外新建一个文件夹,初始化成「裸仓库(bare repo)」——裸仓库没有工作目录,只用来接收推送,不能直接在里面改代码。再写一个 post-receive 钩子脚本,让服务器每次收完推送的最后一个字节后,自动把仓库内容检出(checkout)到真正对外公开的 wp-content 目录。最后在本地把这个远程仓库加为 Git 的 remote,处理本地分支名(main)和 DreamHost 默认分支名(master)不一致的问题,第一次成功推送。
涉及文件
~/我的仓库文件夹/hooks/post-receive(线上服务器新建,Shell 脚本)
代码实现
在线上服务器(SSH 会话里)创建裸仓库:
# 在公开网站目录之外新建一个文件夹(名字随意,这里叫 our-repo)
mkdir our-repo
cd our-repo
# 确认当前路径
pwd
# 初始化为裸仓库——没有工作目录,只用来接收 push
git init --bare
hooks/post-receive(裸仓库自带的 hooks 文件夹里新建这个文件,无扩展名):
#!/bin/bash
git --work-tree=/home/你的SSH用户名/你的域名/wp-content --git-dir=/home/你的SSH用户名/our-repo checkout -f
创建 + 编辑 + 赋可执行权限的命令:
cd hooks
touch post-receive
nano post-receive
# 粘贴/输入上面的脚本内容,Ctrl+X → Y → Enter 保存
chmod +x post-receive
本地(VS Code 终端,在 wp-content 仓库里)添加远程仓库、处理分支名、首次推送:
# 添加远程仓库,取个昵称叫 live,指向刚创建的裸仓库
git remote add live ssh://你的SSH用户名@你的域名/home/你的SSH用户名/our-repo
# 如果地址填错了,用 set-url 更正(不用重新 add)
git remote set-url live ssh://你的SSH用户名@你的域名/home/你的SSH用户名/our-repo
# 查看当前本地分支名
git status
# DreamHost 默认认的分支名是 master,不是新版 Git/Apple 自带 Git 默认的 main
# 如果本地分支是 main,创建并切换到一个叫 master 的新分支(从 main 派生)
git checkout -b master
# 改动文件后,照常提交
git add -A
git commit -m "changed home page title"
# 推送到线上(第一次会要求输入 SSH 密码;因为是第一次推送,会传送仓库里的全部文件)
git push live master
关键改动点:
- 裸仓库故意建在网站公开目录之外(比如跟
logs、maildir平级的位置),因为 push 的过程本身是「服务器管理层面」的操作,不应该发生在对外公开的目录里;等推送完全接收完毕,post-receive钩子再负责把文件复制/检出到真正公开可访问的位置 post-receive是 Git 内置的钩子机制之一(还有pre-commit、post-merge等,都是裸仓库hooks文件夹里自动生成的示例文件),文件名必须精确匹配post-receive,才会在「服务器完整接收完一次 push」之后自动执行- 钩子脚本的核心是一行
git --work-tree=... --git-dir=... checkout -f:--git-dir指向裸仓库自己的位置(存版本历史的地方),--work-tree指向真正要把文件铺开的公开目录(这里specifically 是网站域名文件夹下的wp-content),checkout -f强制检出,确保这一步不管什么情况都会执行 - 脚本第一行
#!/bin/bash用来指定这个脚本要用哪个 shell 解释器执行,是 Linux shell 脚本的标准写法 chmod +x给脚本文件加上可执行权限——新建的文件默认没有执行权限,钩子脚本不可执行的话,post-receive事件触发了也不会真正跑起来- DreamHost 服务器端默认认的分支名固定是
master;较新版本的 Git(尤其是 macOS 自带版本)新建仓库默认分支名是main——作者尝试过多种方法把服务器端改成认main,都没有稳定生效,所以最终采用「反过来让本地分支改名去匹配服务器」这个更省心的折中方案:git checkout -b master会基于当前分支创建一个新分支master并自动切换过去
常见坑
- 裸仓库建在网站公开目录里面——推送过程本身不应该发生在公开可访问的路径下,必须建在外面,靠
post-receive钩子间接把内容同步到公开目录 post-receive文件名拼错(比如少个字母)——钩子文件名必须完全精确匹配 Git 认的固定名称,拼错的话 Git 根本不会去执行它,不会有任何报错提示,只会表现成「push 成功了但网站没更新」- 忘记给
post-receive加可执行权限(chmod +x)——脚本内容写对了但没有执行权限,一样不会生效 - 本地分支名(
main)和服务器认的分支名(master)不一致——推送时容易搞不清到底该 push 到哪个分支,统一改成跟服务器一致最省心 git remote add时手滑打错用户名/域名——作者在录制时真实遇到过这个问题,报错是「fatal: 这看起来不是一个 git 仓库」,遇到这种情况不用重新add,用git remote set-url直接改正 URL 即可
延伸 / 后续讲座会用到
现在 git push 已经能把改动送上线,但每次推送都要输入密码。下一讲会配置 SSH Key 实现免密登录/推送,是这套自动化工作流的最后一块拼图。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 21, EP118