iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0
自我挑戰組

30天 Git 版本控制實戰筆記系列 第 16

Day 16:Git Hooks 自動化 - 讓 Git 自動幫你做事

  • 分享至 

  • xImage
  •  

今日目標
• 理解 Git Hooks 的概念和用途
• 學會建立和使用常用的 Hooks
• 實作自動化檢查和任務
• 提升開發效率和程式碼品質
什麼是 Git Hooks?
簡單比喻:
Git Hooks = 在特定時機自動執行的腳本

就像設定鬧鐘:

  • 每天早上 7 點 → 自動播放音樂
  • Git commit 時 → 自動檢查程式碼
  • Git push 時 → 自動執行測試
    職場真實情況:
    ❌ 沒有 Hooks:
    開發者 commit 後才發現...
  • 忘記跑測試
  • 有語法錯誤
  • commit 訊息格式錯誤
  • 有敏感資訊沒刪除
    → 要重新修改,浪費時間

✅ 使用 Hooks:
Git 在 commit 前自動檢查

  • ❌ 語法錯誤 → 阻止 commit
  • ❌ 測試失敗 → 阻止 commit
  • ❌ 格式錯誤 → 阻止 commit
  • ✅ 全部通過 → 允許 commit
    → 節省時間,提高品質

操作步驟
步驟1:認識 Hooks 資料夾
查看 Hooks 位置:

進入專案

cd company-website

Hooks 存放位置

cd .git/hooks

查看預設的範例

ls -la

你會看到:

pre-commit.sample

pre-push.sample

commit-msg.sample

等等...

Hooks 的運作方式:
.git/hooks/
├── pre-commit # commit 前執行
├── commit-msg # commit 訊息檢查
├── pre-push # push 前執行
├── post-commit # commit 後執行
└── ...
步驟2:建立第一個 Hook - 檢查 commit 訊息
建立 commit-msg Hook:

回到專案根目錄

cd ~/company-website

建立 commit-msg Hook

cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash

讀取 commit 訊息

commit_msg=$(cat "$1")

檢查 commit 訊息格式

if ! echo "$commit_msg" | grep -qE "^(feat|fix|docs|style|refactor|test|chore):"; then
echo "❌ Commit 訊息格式錯誤!"
echo ""
echo "正確格式:"
echo " feat: 新增功能"
echo " fix: 修復問題"
echo " docs: 文件更新"
echo " style: 格式調整"
echo " refactor: 程式碼重構"
echo " test: 測試相關"
echo " chore: 其他雜項"
echo ""
echo "你的訊息:"
echo " $commit_msg"
exit 1
fi

echo "✅ Commit 訊息格式正確!"
EOF

給予執行權限

chmod +x .git/hooks/commit-msg
測試 Hook:

嘗試用錯誤格式 commit

echo "test" > test.txt
git add test.txt
git commit -m "add test file"

❌ 應該會被阻止

用正確格式 commit

git commit -m "feat: 新增測試檔案"

✅ 應該會成功

步驟3:建立 pre-commit Hook - 自動檢查
建立基本檢查:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

echo "🔍 執行 pre-commit 檢查..."

檢查1:防止 commit 大檔案

echo "📦 檢查檔案大小..."
max_size=5242880 # 5MB
for file in $(git diff --cached --name-only); do
if [ -f "$file" ]; then
size=$(wc -c < "$file")
if [ $size -gt $max_size ]; then
echo "❌ 錯誤:檔案 $file 太大 ($(($size/1024/1024))MB)"
echo " 最大允許大小:5MB"
exit 1
fi
fi
done
echo "✅ 檔案大小檢查通過"

檢查2:防止 commit 敏感資訊

echo "🔐 檢查敏感資訊..."
if git diff --cached | grep -iE "(password|secret|api_key|token)" > /dev/null; then
echo "❌ 警告:偵測到可能的敏感資訊!"
echo " 請檢查是否包含密碼、API key 等敏感資料"
echo ""
echo "發現的內容:"
git diff --cached | grep -iE "(password|secret|api_key|token)" --color
echo ""
read -p "確定要繼續 commit 嗎? (y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
echo "✅ 敏感資訊檢查通過"

檢查3:檢查 HTML 基本語法

echo "🌐 檢查 HTML 語法..."
for file in $(git diff --cached --name-only | grep ".html$"); do
if [ -f "$file" ]; then
if ! grep -q "" "$file"; then
echo "❌ 錯誤:$file 缺少 標籤"
exit 1
fi
if ! grep -q "" "$file"; then
echo "❌ 錯誤:$file 缺少 結束標籤"
exit 1
fi
fi
done
echo "✅ HTML 語法檢查通過"

echo "🎉 所有檢查通過!準備 commit..."
EOF

chmod +x .git/hooks/pre-commit
測試 pre-commit Hook:

測試1:嘗試 commit 包含敏感字的檔案

echo "password = 123456" > config.txt
git add config.txt
git commit -m "feat: 新增設定檔"

應該會警告

測試2:嘗試 commit 錯誤的 HTML

echo "no closing tag" > bad.html
git add bad.html
git commit -m "feat: 新增頁面"

應該會被阻止

步驟4:建立 pre-push Hook - 推送前檢查
建立 pre-push Hook:
cat > .git/hooks/pre-push << 'EOF'
#!/bin/bash

echo "🚀 執行 pre-push 檢查..."

檢查1:確保在正確的分支

current_branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$current_branch" = "main" ]; then
echo "⚠️ 警告:你正在推送到 main 分支"
read -p "確定要推送到 main 嗎?(y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
echo "❌ 取消推送"
exit 1
fi
fi

檢查2:確保本地是最新的

echo "🔄 檢查是否需要 pull..."
git fetch origin
LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u} 2>/dev/null)

if [ "$LOCAL" != "$REMOTE" ]; then
echo "❌ 錯誤:你的本地版本不是最新的"
echo " 請先執行 git pull"
exit 1
fi
echo "✅ 版本檢查通過"

檢查3:確保沒有未提交的變更

if ! git diff-index --quiet HEAD --; then
echo "❌ 錯誤:有未提交的變更"
echo " 請先 commit 所有變更"
git status --short
exit 1
fi
echo "✅ 工作目錄檢查通過"

echo "🎉 所有檢查通過!開始推送..."
EOF

chmod +x .git/hooks/pre-push
步驟5:建立 post-commit Hook - commit 後通知
建立 post-commit Hook:
cat > .git/hooks/post-commit << 'EOF'
#!/bin/bash

取得最新的 commit 資訊

commit_msg=$(git log -1 --pretty=%B)
commit_hash=$(git log -1 --pretty=%h)
author=$(git log -1 --pretty=%an)

顯示提交成功訊息

echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "✅ Commit 成功!"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "📝 訊息:$commit_msg"
echo "🔖 Hash:$commit_hash"
echo "👤 作者:$author"
echo "⏰ 時間:$(date '+%Y-%m-%d %H:%M:%S')"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""

可以在這裡加入其他自動化任務

例如:自動執行測試、更新文件等

EOF

chmod +x .git/hooks/post-commit


實用 Hooks 範例
範例1:自動格式化程式碼
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

echo "🎨 自動格式化程式碼..."

格式化 JavaScript 檔案(如果有 prettier)

if command -v prettier &> /dev/null; then
for file in $(git diff --cached --name-only | grep ".js$"); do
if [ -f "$file" ]; then
prettier --write "$file"
git add "$file"
echo "✅ 格式化:$file"
fi
done
fi

移除行尾空白

for file in $(git diff --cached --name-only); do
if [ -f "$file" ]; then
sed -i 's/[[:space:]]*$//' "$file"
git add "$file"
fi
done

echo "✅ 格式化完成"
EOF

chmod +x .git/hooks/pre-commit
範例2:檢查 TODO 註解
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash

echo "📝 檢查 TODO 註解..."

檢查新增的 TODO

todos=$(git diff --cached | grep "^+.*TODO" || true)

if [ ! -z "$todos" ]; then
echo "⚠️ 警告:新增了 TODO 註解"
echo "$todos"
echo ""
read -p "確定要繼續嗎?(y/N) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi

echo "✅ 檢查完成"
EOF

chmod +x .git/hooks/pre-commit
範例3:防止直接 push 到 main
cat > .git/hooks/pre-push << 'EOF'
#!/bin/bash

protected_branch='main'
current_branch=$(git symbolic-ref HEAD | sed -e 's,./(.),\1,')

if [ "$current_branch" = "$protected_branch" ]; then
echo "❌ 錯誤:不允許直接推送到 $protected_branch 分支"
echo " 請使用 Pull Request 流程"
exit 1
fi

echo "✅ 分支檢查通過"
EOF

chmod +x .git/hooks/pre-push


常用 Git Hooks 總覽
Commit 相關:
pre-commit # commit 前執行(最常用)
prepare-commit-msg # 準備 commit 訊息時
commit-msg # 檢查 commit 訊息
post-commit # commit 後執行
Push 相關:
pre-push # push 前執行(很常用)
post-push # push 後執行(較少用)
其他:
pre-rebase # rebase 前執行
post-checkout # checkout 後執行
post-merge # merge 後執行


Hooks 管理最佳實踐
✅ 建議做法:

  1. 使用專案共享 Hooks:

建立 hooks 資料夾

mkdir -p .githooks

將 hooks 放在版本控制中

mv .git/hooks/pre-commit .githooks/

設定 git 使用這個資料夾

git config core.hooksPath .githooks

現在 hooks 可以被 commit 和分享了

git add .githooks/
git commit -m "chore: 新增專案 git hooks"
2. 提供安裝腳本:

建立 setup-hooks.sh

cat > setup-hooks.sh << 'EOF'
#!/bin/bash
echo "安裝 Git Hooks..."
cp .githooks/* .git/hooks/
chmod +x .git/hooks/*
echo "✅ Hooks 安裝完成"
EOF

chmod +x setup-hooks.sh
3. 在 README 說明:

開發環境設定

安裝 Git Hooks:

./setup-hooks.sh
這會啟用以下自動檢查:
•	✅ Commit 訊息格式檢查
•	✅ 程式碼語法檢查
•	✅ 敏感資訊偵測

### **⚠️ 注意事項:**
□ Hooks 不會自動複製到其他人的電腦 □ 需要團隊成員手動安裝 □ 可以用 core.hooksPath 統一管理 □ Hooks 執行失敗會阻止操作 □ 可以用 --no-verify 跳過檢查(不建議)

---

## **跳過 Hooks(緊急情況)**

```bash
# 跳過 pre-commit 檢查
git commit --no-verify -m "緊急修復"

# 跳過 pre-push 檢查
git push --no-verify
⚠️ 警告:只在緊急情況使用,會跳過所有安全檢查!
________________________________________
今日重點回顧
•	✅ 理解 Git Hooks 的運作原理
•	✅ 建立常用的 Hooks 腳本
•	✅ 實作自動化檢查流程
•	✅ 學會管理和分享 Hooks
核心概念總結
.git/hooks/              # Hooks 存放位置
pre-commit              # commit 前檢查
commit-msg              # 訊息格式檢查
pre-push                # push 前檢查
post-commit             # commit 後通知

chmod +x .git/hooks/*   # 給予執行權限
git commit --no-verify  # 跳過 hooks(緊急用)


上一篇
Day 15:Git 歷史查詢與分析 - 成為 Git 偵探
下一篇
Day 17:大型專案管理策略 - 管理複雜的程式碼庫
系列文
30天 Git 版本控制實戰筆記19
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言