前言
在現代軟體開發流程中,自動化部署是提升效率與減少人為錯誤的關鍵一環。許多開發者習慣在本地測試無誤後,手動透過 FTP 或 SCP 將檔案上傳至伺服器,這種方式不僅效率低落,在多人協作時更容易產生版本衝突。
Git Hook 提供了一個強大的機制,讓我們能在 Git 事件觸發時(例如程式碼推送完成後),自動執行腳本。透過配置 post-receive hook,我們可以实现「推送即部署」的無縫體驗。這篇文章將帶領你逐步設定一個基於 Git Hook 的自動化部署環境,適合具備基礎 Linux 操作能力的中階使用者。
環境準備與目錄結構
首先,我們需要明確區分「Git 倉庫」與「Web 根目錄」。為了安全起見,我們不建議直接在 Git 倉庫內進行部署,而是使用一個「裸倉庫」(Bare Repository)作為接收端,並將內容部署到另一個獨立的目錄。
假設我們使用 www-data 使用者來運行 Web 服務,並建立以下目錄結構:
/var/git/project.git:Git 裸倉庫,用於接收推送。/var/www/html:實際的 Web 根目錄,供瀏覽器存取。
請先建立這些目錄並設定正確的權限:
# 建立 Git 倉庫目錄
sudo mkdir -p /var/git/project.git
cd /var/git/project.git
# 初始化裸倉庫
sudo git init --bare
# 建立 Web 根目錄並設定權限,讓 www-data 有權寫入
sudo mkdir -p /var/www/html
sudo chown -R www-data:www-data /var/www/html
配置 Post-Receive Hook
接下來,我們要在裸倉庫中創建 post-receive 腳本。這個腳本會在每次成功接收推送後執行。
在 /var/git/project.git/hooks/ 目錄下建立名為 post-receive 的檔案:
sudo nano /var/git/project.git/hooks/post-receive
輸入以下內容。這段腳本的邏輯是:從裸倉庫中提取最新程式碼,並覆蓋到 /var/www/html 目錄。
#!/bin/bash
# 定義部署目標路徑
DEPLOY_PATH="/var/www/html"
# 從標準輸入讀取推送資訊,並獲取當前分支名稱
while read oldrev newrev refname
do
branch=$(git rev-parse --symbolic --abbrev-ref "$refname")
# 僅在推送到 main 分支時執行部署
if [ "$branch" == "main" ]; then
echo "Deploying to $DEPLOY_PATH..."
# 清除舊檔案並提取最新內容
# --force 確保覆蓋現有檔案
git --work-tree=$DEPLOY_PATH --git-dir=/var/git/project.git checkout -f $branch
echo "Deployment successful!"
else
echo "Ignoring push to non-main branch: $branch"
fi
done
寫入檔案後,務必賦予該腳本執行權限,否則 Git 將忽略它:
sudo chmod +x /var/git/project.git/hooks/post-receive
設定 Git 權限與防火牆
為了讓自動化部署順利運作,我們需要確保 Git 倉庫的擁有者是 www-data,這樣腳本執行時才有權限寫入 Web 目錄。
sudo chown -R www-data:www-data /var/git/project.git
此外,如果你的伺服器啟用了防火牆(如 UFW),請確保 SSH 端口(預設 22)是開放的,以便從本地電腦推送程式碼:
sudo ufw allow ssh
從本地推送程式碼
現在,回到你的本地開發環境。首先,將你的專案初始化為 Git 倉庫(如果尚未初始化),然後將遠端地址指向伺服器的裸倉庫。
假設你的伺服器 IP 為 192.168.1.100,使用者為 root 或具有 sudo 權限的使用者:
# 在本地專案目錄執行
git init
git add .
git commit -m "Initial commit"
# 添加遠端倉庫
git remote add production ssh://root@192.168.1.100/var/git/project.git
# 推送程式碼到 main 分支
git push production main
推送過程中,系統會詢問伺服器密碼。輸入正確密碼後,Git 會將程式碼傳送至伺服器。由於我們配置了 post-receive hook,伺服器會自動將內容提取到 /var/www/html。你可以登入伺服器檢查該目錄,確認檔案是否已同步。
常見問題
1. 推送後網頁內容未更新
如果推送成功但網頁內容沒有改變,請檢查以下幾點:
- 權限問題:確保
/var/www/html目錄的所有者是www-data,且post-receive腳本有執行權限。 - 緩存問題:瀏覽器或伺服器(如 Nginx/Apache)可能有快取,嘗試清除快取或強制重新整理。
- 分支名稱:確認
post-receive腳本中的分支名稱(如main)與你推送的分支名稱完全一致。
2. 安全性風險
將部署權限交給 Git Hook 可能帶來安全隱患。建議採取以下措施:
- 限制推送權限:不要使用
root帳號進行日常推送。建立一個專門的部署使用者(如deployer),並透過 SSH 金鑰對驗證,僅允許該使用者推送程式碼。 - 隔離目錄:確保 Git 倉庫與 Web 根目錄分離,避免直接暴露
.git目錄到網路。 - 腳本驗證:在
post-receive中加入更嚴格的驗證邏輯,例如檢查提交者身份或簽章,防止惡意推送。
小結
透過配置 Git Hook,我們成功建立了一個簡潔的自動化部署流程。這不僅減少了手動上傳的繁瑣步驟,也確保了開發環境與生產環境的一致性。雖然此範例展示了基本的部署邏輯,但在實際生產環境中,建議進一步結合 CI/CD 工具(如 Jenkins 或 GitLab CI)來處理更複雜的構建與測試步驟。希望這篇文章能幫助你邁向更高效能的 DevOps 工作流程。