Git钩子实现GitLab仓库从Server A到Server B镜像同步问题
解决GitLab仓库自动镜像同步的钩子生效问题
我之前帮朋友排查过类似的GitLab钩子不生效的问题,大概率是钩子的配置细节或者运行环境出了问题,咱们一步步来搞定:
1. 先检查钩子的基础配置(最容易踩坑的点)
Git钩子要生效,必须满足几个硬性条件,缺一不可:
- 文件位置:必须放在Server A上GitLab仓库的
.git/hooks目录下。如果是GitLab托管的仓库,默认路径一般是/var/opt/gitlab/git-data/repositories/<你的命名空间>/<仓库名>.git/hooks(比如/var/opt/gitlab/git-data/repositories/test-group/my-repo.git/hooks)。 - 文件名:必须是
post-receive,不能加任何后缀(比如post-receive.sh是无效的)。 - 权限设置:给钩子加上可执行权限:
chmod +x post-receive - 所有者正确:钩子文件的所有者必须是GitLab的运行用户(通常是
git),否则GitLab没权限执行它:chown git:git post-receive
2. 编写正确的post-receive钩子脚本
钩子运行的环境和你手动执行命令的环境不一样,比如环境变量缺失、认证信息不对,都会导致git push --mirror失败。这里给你一个经过验证的脚本模板:
#!/bin/bash # 目标镜像仓库地址 TARGET_REPO="http://example.com/test-repo.git" # 确保Git命令能被找到(GitLab钩子的环境PATH可能不包含git路径) export PATH=/usr/bin:$PATH # -------------------------- 认证处理(关键!)-------------------------- # 推荐用SSH密钥免密认证:把Server A上git用户的公钥添加到Server B仓库的部署密钥中 # 1. 切换到git用户:sudo su - git # 2. 生成密钥(如果没有的话):ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa # 3. 复制~/.ssh/id_rsa.pub的内容,添加到Server B仓库的部署密钥里 # 如果必须用HTTP/HTTPS,可以用Git凭证存储(避免明文密码): # 切换到git用户后执行: # git config --global credential.helper store # 然后手动执行一次git push --mirror,输入用户名密码后会自动存储到~/.git-credentials # -------------------------- 执行镜像推送并记录日志 -------------------------- # 记录日志方便排查问题,日志路径可以自己改 LOG_FILE="/var/log/git-mirror-$(basename $TARGET_REPO .git).log" echo "===== $(date) 开始镜像同步 =====" >> $LOG_FILE git push --mirror "$TARGET_REPO" >> $LOG_FILE 2>&1 EXIT_CODE=$? echo "===== 同步结束,退出码:$EXIT_CODE =====" >> $LOG_FILE
3. 排查GitLab的特殊限制
- 测试手动推送:切换到
git用户(sudo su - git),手动执行git push --mirror http://example.com/test-repo.git。如果手动都失败,那钩子肯定也不行,先解决这个问题——通常是认证或者网络连通性的问题。 - 检查钩子是否触发:可以在脚本开头加一行测试代码:
然后在本地推一次代码到Server A,查看echo "post-receive钩子已触发:$(date)" >> /tmp/git-hook-test.log/tmp/git-hook-test.log有没有内容。如果没有,说明钩子根本没触发,回到第一步检查文件配置;如果有,说明钩子触发了,那就是git push命令的问题,看日志文件里的错误信息。
4. 常见问题排查
- 认证失败:如果日志里出现
Permission denied,大概率是SSH密钥没配置对,或者HTTP凭证没存储到git用户的目录下。 - Git命令找不到:如果日志里出现
git: command not found,说明PATH没设对,把export PATH里的路径改成你实际的Git安装路径(可以用which git查看)。 - GitLab钩子被覆盖:如果是GitLab 11.0以上版本,默认允许自定义钩子,但如果你用了GitLab的Web钩子,不会影响post-receive钩子的执行,两者是独立的。
按照上面的步骤来,基本就能解决钩子不生效的问题了!
内容的提问来源于stack exchange,提问作者learnthinkact




