Git post-receive钩子无法工作?远程自动部署配置问题求助
看起来你遇到的问题我之前也碰到过,结合你提到的“手动运行脚本正常但钩子不触发”,咱们一步步排查,顺便理清钩子的核心工作逻辑:
先纠正一个可能的基础误解
post-receive钩子只有当仓库收到git push操作时才会自动触发,如果你的远程服务器是通过git pull从GitHub拉取代码,那这个操作不会触发钩子——因为拉取是主动获取变更,不是接收推送。如果你的最终需求是“本地推GitHub后远程自动部署”,可能需要调整流程(比如用GitHub Webhook触发远程脚本),不过先聚焦解决当前钩子不触发的问题。
排查钩子不触发的常见原因
1. 钩子文件权限不对
Git要求钩子脚本必须有可执行权限,手动运行没问题是因为你用自己的用户权限执行,但Git触发钩子时用的是仓库运行的用户权限。执行下面的命令给脚本加权限:
chmod +x /path/to/your/repo/.git/hooks/post-receive
另外还要检查文件所有权,确保Git进程能读取并执行它,比如如果服务器用nginx/apache用户运行应用,要确保文件所属组是对应的用户组。
2. 钩子文件名错误
Git钩子的文件名必须严格是post-receive,不能加任何后缀(比如post-receive.sh就不行)。很多人习惯给脚本加.sh后缀,但Git只会识别没有后缀的钩子文件,先检查下你的文件名是否正确。
3. 远程仓库不是裸仓库(Bare Repository)
如果你的远程服务器上的仓库是普通仓库(有工作目录的那种),Git默认会禁止推送操作(避免和本地工作目录冲突),自然也不会触发post-receive钩子。部署用的仓库应该是裸仓库,创建方式是:
git init --bare myapp.git
如果已经是普通仓库,可以转成裸仓库,或者修改Git配置允许推送:
git config receive.denyCurrentBranch updateInstead
不过更推荐用裸仓库作为接收推送的目标,然后通过GIT_WORK_TREE指定部署目录,这也是你脚本里的做法。
4. 给钩子加日志排查细节
手动运行正常但钩子不触发,大概率是Git执行钩子时的环境变量和你手动运行时不一样。在脚本开头加日志输出,方便定位问题:
#!/bin/sh # 把日志输出到指定文件,方便排查 exec >> /home/me/git-deploy.log 2>&1 echo "=== 钩子触发时间:$(date) ===" # 打印环境变量,查看Git的执行环境是否正常 env # 执行部署命令 GIT_WORK_TREE=/home/me/webapps/myapp git checkout -f master GIT_WORK_TREE=/home/me/webapps/myapp git reset --hard echo "=== 部署完成 ==="
然后重新推送代码,查看/home/me/git-deploy.log:
- 如果日志文件没生成:说明钩子根本没被Git调用,回到前面的权限、文件名、仓库类型排查;
- 如果日志有错误信息:比如找不到Git命令、权限不足,就针对性解决。
5. 确认推送分支和钩子逻辑匹配
你的脚本里操作的是master分支,要确保你推送到远程仓库的确实是master分支。如果推的是其他分支,钩子脚本里没有对应处理,也会看起来像没触发(其实触发了但没执行有效操作)。
适配需求的流程调整
如果你的最终目标是“本地推GitHub后远程服务器自动部署”,除了让远程仓库接收GitHub的推送外,更简单的方式是用GitHub的Webhook:当你推GitHub时,GitHub发送一个请求到你的远程服务器,触发部署脚本(比如拉取GitHub代码、重启服务等),这种方式比钩子更适合跨服务器的部署场景。
内容的提问来源于stack exchange,提问作者Richard

