我們通常需要在 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