我们通常需要在 PUSH 代码到远程仓库时,线上环境会自动进行代码同步,这时候就需要用到WebHook,它会自动回调我们设定的http地址。
通过请求我们自已编写的脚本,来拉取代码,实现与远程仓库代码的同步。
一、我们先创建一个本地仓库
echo "# 测试" > README.md git init git add README.md git commit -m "test"
在码云或 GitHub 上创建一个空仓库,比如:test,然后让本地仓库与远程仓库关联。
git remote add origin https://gitee.com/xxx/test.git git push -u origin master
二、在本地仓库,添加WebHook文件,并提交到版本库
码云版:
<?php $data = json_decode(file_get_contents('php://input'), true); // 码云WebHooks中配置的密码 $password = "123456"; // 你本地的项目路径 $path = "/data/wwwroot/test"; // 判断密码 if ($data['password'] === $password) { echo shell_exec("id -a"); echo shell_exec("cd {$path} && /usr/bin/git reset --hard origin/master && /usr/bin/git clean -f && /usr/bin/git pull 2>&1"); exit(); } http_response_code(404);
GitHub版:
<?php // GitHub项目 Settings/Webhooks 中的 Secret $secret = "123456"; // 你本地的项目路径 $path = "/data/wwwroot/test"; // 验签 $signature = $_SERVER['HTTP_X_HUB_SIGNATURE']; if ($signature) { $hash = "sha1=" . hash_hmac('sha1', file_get_contents("php://input"), $secret); if (strcmp($signature, $hash) == 0) { echo shell_exec("id -a"); echo shell_exec("cd {$path} && /usr/bin/git reset --hard origin/master && /usr/bin/git clean -f && /usr/bin/git pull 2>&1"); exit(); } } http_response_code(404);
三、登陆线上服务器,为用户生成 SSH 秘钥,并配置码云或GitHub的项目公钥。
配置公钥主要的作用是免去每次 git 操作时需要输入密码。
注意,这里,我们要为 www 用户或 nobody 用户生成 ssh 秘钥,别搞错了。webhook 调用时,是 php 脚本当前执行的用户。
具体是哪个用户可以通过 echo shell_exec('id -a'); 来查看。
sudo mkdir -p /home/www/.ssh sudo chown -R www.www /home/www/.ssh sudo -Hu www ssh-keygen -t rsa
一路回车,直到结束,系统会在用户的家目录,生成 id_rsa 和 id_rsa.pub 两个文件,即 id_rsa 密钥 和 id_rsa.pub 公钥。
cat /home/www/.ssh/id_rsa.pub
然后在 码云 项目管理 -> 公钥管理 -> 添加公钥 ,把 id_rsa.pub 中的内容添加。
在GitHub 账号 -> Setting -> SSH and GPG keys ,把 id_rsa.pub 中的内容添加。
然后分别在码云和 GitHub 项目配置WebHook,注意地址必须能外网访问的。
四、登陆线上服务器,并使用 ssh 协议 clone 项目
注意,我们配置了项目的 ssh 公钥,拉取项目要走 ssh 协议,而不是 https。
sudo -u www git clone git@gitee.com:xxx/test.git
注意,如果报错, fatal: 不能创建工作区目录 'test': 权限不够 ,则需要创建一个同名 test 目录,并把目录所属用户修改成 www。
chown -R www.www test
修改权限,注意你PHP运行时的用户是谁,一般为www,也有可能是 nobody
sudo chown -R www . sudo chmod -R g+s . sudo -u www git pull
在本地提交文件,就可以看到代码自动同步到线上服务器了。
五、基于不同分支,来同步不同目录下的代码
这里以gitee为例:
<?php $data = json_decode(file_get_contents('php://input'), true); // 码云WebHooks中配置的密码 $password = "123456"; // 你本地的项目路径 $paths = [ 'master' => '/data/www/wwwroot/master', 'test' => '/data/www/wwwroot/test', 'develop' => '/data/www/wwwroot/develop', ]; // 获取分支名 $ref = explode('/', $data['ref']); $branch = end($ref); // 判断密码 if ($data['password'] === $password && $data['total_commits_count'] > 0 && $paths[$branch] ) { $path = $paths[$branch]; echo shell_exec("id -a"); echo shell_exec("cd {$path} && /usr/bin/git checkout {$branch} 2>&1"); echo shell_exec("cd {$path} && /usr/bin/git reset --hard origin/{$branch} && /usr/bin/git clean -f && /usr/bin/git pull origin {$branch} 2>&1"); exit(); } http_response_code(404);
我们在本地创建三个目录,分别对应三个分支,其中一个分支代码更新时,则自动同步。
注意,本地通过 sudo -u www git clone xxx 拉取代码后,切换分支时,也需要指定用户,不然会有权限问题。
sudo -u www git checkout develop