今日目標
• 理解 Git Hooks 的概念和用途
• 學會建立和使用常用的 Hooks
• 實作自動化檢查和任務
• 提升開發效率和程式碼品質
什麼是 Git Hooks?
簡單比喻:
Git Hooks = 在特定時機自動執行的腳本
就像設定鬧鐘:
✅ 使用 Hooks:
Git 在 commit 前自動檢查
操作步驟
步驟1:認識 Hooks 資料夾
查看 Hooks 位置:
cd company-website
cd .git/hooks
ls -la
Hooks 的運作方式:
.git/hooks/
├── pre-commit # commit 前執行
├── commit-msg # commit 訊息檢查
├── pre-push # push 前執行
├── post-commit # commit 後執行
└── ...
步驟2:建立第一個 Hook - 檢查 commit 訊息
建立 commit-msg Hook:
cd ~/company-website
cat > .git/hooks/commit-msg << 'EOF'
#!/bin/bash
commit_msg=$(cat "$1")
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:
echo "test" > test.txt
git add test.txt
git commit -m "add test file"
git commit -m "feat: 新增測試檔案"
步驟3:建立 pre-commit Hook - 自動檢查
建立基本檢查:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
echo "🔍 執行 pre-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 "✅ 檔案大小檢查通過"
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 "✅ 敏感資訊檢查通過"
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:
echo "password = 123456" > config.txt
git add config.txt
git commit -m "feat: 新增設定檔"
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 檢查..."
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
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 "✅ 版本檢查通過"
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_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 "🎨 自動格式化程式碼..."
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 註解..."
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 管理最佳實踐
✅ 建議做法:
mkdir -p .githooks
mv .git/hooks/pre-commit .githooks/
git config core.hooksPath .githooks
git add .githooks/
git commit -m "chore: 新增專案 git hooks"
2. 提供安裝腳本:
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(緊急用)