跳至主要内容

Git Hooks 工程指南

自動化工作流並強制執行工程標準

Git hooks 是 Git 在關鍵事件(如 commit, push, receive)前後自動執行的腳本。它們對於維護代碼質量、確保安全性以及自動化重複性的開發任務至關重要。

核心概念

Hook 分類

類別Hooks作用範圍
客戶端 (Client-Side)pre-commit, commit-msg, pre-push本地開發工作流
服務端 (Server-Side)pre-receive, post-receive, update遠端倉庫強制執行

客戶端與服務端 Hooks 的區別

客戶端 Hooks 在開發者的本地機器上運行。它們充當個人防護欄 — 執行快速的 linting、格式化和提交信息驗證等檢查。客戶端 Hooks 可以通過 --no-verify 跳過,因此屬於建議性而非強制性。

服務端 Hooks 在遠端倉庫(如 GitHub、GitLab、自建 Git 伺服器)上運行。它們強制執行不可跳過的策略,例如拒絕未通過 CI 檢查的推送、強制執行分支命名規範,或禁止對受保護分支執行 force-push。

經驗法則:客戶端 Hooks 用於提升開發體驗(快速反饋),服務端 Hooks 用於策略執行(不可繞過的規則)。

為什麼要使用 Hooks 自動化?

收益工程成果
代碼質量防止 linting/formatting 錯誤進入版本庫。
安全性在代碼離開本地機器前掃描硬編碼的密鑰(Secrets/API keys)。
標準化強制執行 Conventional Commits 規範。
可靠性確保單元測試通過後才允許執行 push 操作。

Hook 管理工具

原生 Git hooks(存儲在 .git/hooks/ 中)不易進行版本控制。Hook 管理工具通過使 hooks 可共享、可配置且易於維護來解決這一問題。根據項目的生態系統選擇合適的工具:

管理工具語言適用場景並行執行
Husky + lint-stagedNode.jsnpm/Node.js 項目通過 lint-staged
LefthookGo 二進制多語言 / 任意工具鏈內建支持
pre-commitPythonPython 或多語言倉庫不支持

Husky + lint-staged (Node.js 生態)

Husky 簡化了 Git hooks 的管理和在團隊內的共享。

# 安裝 Husky
npm install husky --save-dev

# 初始化 Husky (創建 .husky 目錄)
npx husky init

在每次 commit 時對 整個 代碼庫運行 linter 會非常緩慢。lint-staged 確保你只檢查當前正在提交的文件。

npm install lint-staged --save-dev

配置 (package.json):

{
"lint-staged": {
"*.{js,ts,tsx}": "eslint --fix",
"*.py": "ruff check --fix",
"*.md": "prettier --write"
}
}

.husky/pre-commit:

npx lint-staged

Lefthook (語言無關)

一個用 Go 編寫的快速、零依賴的管理工具。與 Husky(僅限 npm)或 pre-commit(Python)不同,Lefthook 適用於任何工具鏈,並內建支持並行執行。

安裝:

# Go
go install github.com/evilmartians/lefthook@latest

# npm
npm install @evilmartians/lefthook --save-dev

# Homebrew (macOS/Linux)
brew install lefthook

配置 (lefthook.yml):

pre-commit:
commands:
lint-js:
glob: "*.{js,ts,tsx}"
run: eslint --fix {staged_files}

format-py:
glob: "*.py"
run: ruff format {staged_files}

commit-msg:
commands:
conventional:
run: commitlint --edit {1}
# 將 hooks 安裝到 .git/ 目錄
lefthook install

pre-commit (Python 生態)

純 Python 或多語言項目的行業標準,擁有豐富的共享 hook 倉庫生態。

pip install pre-commit

.pre-commit-config.yaml:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-added-large-files

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.4.0
hooks:
- id: ruff
args: [ --fix ]
- id: ruff-format
# 將 hooks 安裝到 .git/ 目錄
pre-commit install

# 手動對所有文件運行
pre-commit run --all-files

提交信息工具

標準化的提交信息有助於自動生成變更日誌(Changelog)並提供更好的項目歷史視圖。這些工具通過 commit-msg hook 接入任何 Hook 管理工具。

Commitlint (驗證)

在提交信息寫入後強制執行 Conventional Commit 規範:

npm install @commitlint/cli @commitlint/config-conventional --save-dev

# 創建配置
echo "export default { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js

# 添加 hook
echo "npx commitlint --edit \$1" > .husky/commit-msg

Commitizen (交互式)

Commitizen 通過交互式引導幫助開發者編寫合規的提交信息 — 在驗證之前就消除猜測。

npm install cz-conventional-changelog --save-dev

package.json:

{
"scripts": {
"commit": "cz"
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
}
}

使用 npm run commit(或 npx cz)替代 git commit,系統將交互式地引導你填寫 type、scope 和 description。

兩者配合實現縱深防禦:Commitizen 幫助編寫規範的提交信息,Commitlint 捕獲任何遺漏。


最佳實踐

主動驗證 (Proactive Validation)
  1. 對 Hooks 進行版本控制:永遠不要依賴本地的 .git/hooks/。請使用 Hook 管理工具。
  2. 快速失敗 (Fail Fast):合理安排 hooks 順序,使運行速度最快的檢查(如 linting)先於耗時較長的檢查(如集成測試)運行。
  3. 信息化錯誤提示:確保 hook 腳本在拒絕提交時提供清晰的修復指南。
  4. 謹慎使用 --no-verify:僅在緊急情況下跳過 hooks;絕不要為了規避質量標準而使用。
  5. 虛擬環境感知:Hooks 在裸 shell 環境中執行 — 不會繼承你激活的虛擬環境。請使用 uv runpipx run 等包裝命令或絕對路徑來確保工具能被找到。

常見問題排除

問題解決方案
Hooks 未觸發確保腳本具有執行權限:chmod +x .husky/pre-commit
Husky 初始化失敗確保你位於 Git 倉庫的根目錄下。
環境不匹配在 hook 腳本中使用絕對路徑或標準命令(如 npm run)。
"command not found" 錯誤Hook 在虛擬環境之外運行。請使用 uv runpipx run 前綴或工具的絕對路徑。