Learn Git

Git Hooks

和其他版本控制系統一樣,當某些重要事件發生時,Git 有方法可以觸發自訂腳本。有兩組掛鉤(hooks):用戶端和伺服器端。用戶端掛鉤用於用戶端的操作,如提交和合併。伺服器端掛鉤用於 Git 伺服器端的操作,如接收被推送的提交。你可以為了各種不同的原因使用這些掛鉤,下面會講解其中一些。

安裝一個 Hook

掛鉤都被儲存在 Git 目錄下的 hooks 子目錄中,即大部分專案中預設的 .git/hooks。Git 預設會放置一些腳本範例在這個目錄中,除了可以作為掛鉤使用,這些樣本本身是可以獨立使用的。所有的樣本都是 shell 腳本,其中一些還包含了 Perl 的腳本,不過,任何正確命名的可執行腳本都可以正常使用 — 可以用 Ruby 或 Python,或其他。在 Git 1.6 版本之後,這些樣本檔名都是以 .sample 結尾,因此,你必須重新命名。在 Git 1.6 版本之前,這些樣本名都是正確的,但這些樣本不是可執行檔。

把一個正確命名且可執行的檔放入 Git 目錄下的 hooks 子目錄中,可以啟動該掛鉤腳本,之後他一直會被 Git 呼叫。隨後會講解主要的掛鉤腳本。

用戶端掛鉤

有許多用戶端掛鉤,以下把他們分為:提交工作流程掛鉤、電子郵件工作流程掛鉤及其他用戶端掛鉤。

提交工作流程掛鉤

有四個掛鉤被用來處理提交的過程。pre-commit 掛鉤在鍵入提交資訊前運行,被用來檢查即將提交的快照,例如,檢查是否有東西被遺漏,確認測試是否運行,以及檢查代碼。當從該掛鉤返回非零值時,Git 放棄此次提交,但可以用 git commit --no-verify 來忽略。該掛鉤可以被用來檢查程式碼樣式(運行類似 lint 的程式),檢查尾部空白(預設掛鉤是這麼做的),檢查新方法(簡體中文版譯注:程式的函數)的說明。

prepare-commit-msg 掛鉤在提交資訊編輯器顯示之前,預設資訊被創建之後執行。因此,可以有機會在提交作者看到預設資訊前進行編輯。該掛鉤接收一些選項:擁有提交資訊的檔案路徑,提交類型,以及提交的 SHA-1 (如果這是一個 amended 提交)。該掛鉤對通常的提交來說不是很有用,只在自動產生的預設提交資訊的情況下有作用,如提交資訊範本、合併、壓縮和 amended 提交等。可以和提交範本配合使用,以程式設計的方式插入資訊。

commit-msg 掛鉤接收一個參數,此參數是包含最近提交資訊的暫存檔路徑。如果該掛鉤腳本以非零退出,Git 會放棄提交,因此,可以用來在提交通過前驗證專案狀態或提交資訊。本章上一小節已經展示了使用該掛鉤核對提交資訊是否符合特定的模式。

post-commit 掛鉤在整個提交過程完成後運行,他不會接收任何參數,但可以執行 git log -1 HEAD 來獲得最後的提交資訊。總之,該掛鉤是作為通知之類使用的。

提交工作流程的用戶端掛鉤腳本可以在任何工作流程中使用,他們經常被用來實施某些策略,但值得注意的是,這些腳本在 clone 期間不會被傳送。可以在伺服器端實施策略來拒絕不符合某些策略的推送,但這完全取決於開發者在用戶端使用這些腳本的情況。所以,這些腳本對開發者是有用的,由他們自己設置和維護,而且在任何時候都可以覆蓋或修改這些腳本。

E-mail 工作流掛鉤

有三個可用的用戶端掛鉤用於 e-mail工作流。當運行 git am 命令時,會呼叫他們,因此,如果你沒有在工作流中用到此命令,可以跳過本節。如果你通過 e-mail 接收由 git format-patch 產生的補丁,這些掛鉤也許對你有用。

首先執行的是 applypatch-msg 掛鉤,他接收一個參數:包含被建議提交資訊的暫存檔案名。如果該腳本以非零值退出,Git 將放棄此補丁。可以使用這個腳本確認提交資訊是否被正確格式化,或讓腳本把提交訊息編輯為正規化。

下一個當透過 git am 應用補丁時執行的是 pre-applypatch 掛鉤。該掛鉤不接收參數,在補丁被應用之後執行,因此,可以被用來在提交前檢查快照。你能用此腳本執行測試,檢查工作樹。如果有些什麼遺漏,或測試沒通過,腳本會以非零退出,放棄此次 git am 的運行,補丁不會被提交。

最後在 git am 操作期間執行的掛鉤是 post-applypatch。你可以用他來通知一個小組或該補丁的作者,但無法使用此腳本阻止打補丁的過程。

其他用戶端掛鉤

pre-rebase 掛鉤在衍合前執行,腳本以非零退出可以中止衍合的過程。你可以使用這個掛鉤來禁止衍合已經推送的提交物件,Git 所安裝的 pre-rebase 掛鉤範例就是這麼做的,不過它假定 next 是你定義的分支名。因此,你可能要修改樣本,把 next 改成你定義過且穩定的分支名。

git checkout 成功執行後會執行 post-checkout 掛鉤。他可以用來為你的專案環境設置合適的工作目錄。例如:放入大的二進位檔案、自動產生的文檔或其他一切你不想納入版本控制的檔。

最後,在 merge 命令成功執行後會執行 post-merge 掛鉤。他可以用來在 Git 無法跟蹤的工作樹中恢復資料,例如許可權資料。該掛鉤同樣能夠驗證在 Git 控制之外的檔是否存在,當工作樹改變時,你希望可以複製進來的檔案。

伺服器端掛鉤

除了用戶端掛鉤,作為系統管理員,你還可以使用兩個伺服器端的掛鉤對專案實施各種類型的策略。這些掛鉤腳本可以在提交物件推送到伺服器前執行,也可以在推送到伺服器後執行。推送到伺服器前執行的掛鉤(pre hooks)可以在任何時候以非零退出,拒絕推送、傳回錯誤訊息給用戶端;還可以如你所願設置足夠複雜的推送策略。

pre-receive and post-receive

處理來自用戶端的推送(push)操作時最先執行的腳本就是 pre-receive 。它從標準輸入(stdin)獲取被推送的引用(references)列表;如果它退出時的返回值不是0,那麼所有推送內容都不會被接受。利用此掛鉤腳本可以實現類似保證被更新的索引(references)都不是 non-fast-forward 類型;抑或檢查執行推送操作的用戶擁有創建、刪除或者推送的許可權,或者他是否對將要修改的每一個檔都有存取權限。

post-receive 掛鉤在整個過程完結以後執行,可以用來更新其他系統服務或者通知使用者。它接受與 pre-receive 相同的標準輸入資料。應用實例包括給某郵寄清單發信,通知即時整合資料的伺服器,或者更新軟體專案的問題追蹤系統 —— 甚至可以通過分析提交資訊來決定某個問題是否應該被開啟、修改或結案。該腳本無法停止推送程序,不過用戶端在它完成之前將保持連接狀態;所以在用它作一些長時間的操作之前請三思。

update

update 腳本和 pre-receive 腳本十分類似,除了它會為推送者更新的每一個分支運行一次。假如推送者同時向多個分支推送內容,pre-receive 只執行一次,相較之下 update 則會為每一個更新的分支運行一次。它不會從標準輸入讀取內容,而是接受三個參數:索引(reference)的名字(分支),推送前索引指向的內容的 SHA-1 值,以及使用者試圖推送內容的 SHA-1 值。如果 update 腳本退出時返回非零值,只有相應的那一個索引會被拒絕;其餘的依然會得到更新。