章節 ▾ 第二版

8.3 自定義 Git - Git 鉤子

Git 鉤子

與許多其他版本控制系統類似,Git 可以在某些重要操作發生時觸發自定義指令碼。這些鉤子分為兩組:客戶端鉤子和伺服器端鉤子。客戶端鉤子由提交和合並等操作觸發,而伺服器端鉤子則在接收推送提交等網路操作時執行。你可以出於各種原因使用這些鉤子。

安裝鉤子

所有鉤子都儲存在 Git 目錄的 hooks 子目錄中。在大多數專案中,它就是 .git/hooks。當你使用 git init 初始化一個新的倉庫時,Git 會用一系列示例指令碼填充 hooks 目錄,其中許多指令碼本身就很有用;它們還記錄了每個指令碼的輸入值。所有示例都以 shell 指令碼編寫,其中也包含一些 Perl,但任何命名正確、可執行的指令碼都能正常工作——你可以用 Ruby、Python 或任何你熟悉的語言編寫它們。如果你想使用這些捆綁的鉤子指令碼,你需要重新命名它們;它們的檔名都以 .sample 結尾。

要啟用一個鉤子指令碼,請在你的 .git 目錄的 hooks 子目錄中放置一個命名正確(不帶任何副檔名)且可執行的檔案。從那時起,它就會被呼叫。我們將在本節中介紹大多數主要的鉤子檔名。

客戶端鉤子

客戶端鉤子有很多。本節將它們分為提交工作流鉤子、郵件工作流指令碼和其他。

注意

需要注意的是,當你克隆倉庫時,客戶端鉤子不會被複制。如果你想透過這些指令碼強制執行策略,你可能需要在伺服器端進行;請參閱Git 強制策略示例中的示例。

提交工作流鉤子

前四個鉤子與提交過程有關。

pre-commit 鉤子首先執行,甚至在你輸入提交資訊之前。它用於檢查即將提交的快照,看看你是否遺漏了什麼,確保測試執行,或檢查程式碼中你需要檢查的任何內容。如果此鉤子以非零狀態退出,則會中止提交,儘管你可以使用 git commit --no-verify 繞過它。你可以做諸如檢查程式碼風格(執行 lint 或類似工具)、檢查尾隨空格(預設鉤子正是這樣做的)或檢查新方法是否有適當文件之類的事情。

prepare-commit-msg 鉤子在提交資訊編輯器啟動之前但在預設資訊建立之後執行。它允許你在提交作者看到預設資訊之前對其進行編輯。此鉤子接收幾個引數:包含當前提交資訊的檔案路徑、提交型別以及(如果是修改提交)提交的 SHA-1 值。此鉤子通常不適用於普通提交;相反,它適用於預設資訊是自動生成的提交,例如模板提交資訊、合併提交、壓縮提交和修改提交。你可以將其與提交模板結合使用,以程式設計方式插入資訊。

commit-msg 鉤子接收一個引數,它同樣是包含開發者編寫的提交資訊的臨時檔案路徑。如果此指令碼以非零狀態退出,Git 將中止提交過程,因此你可以使用它在允許提交透過之前驗證你的專案狀態或提交資訊。在本章的最後一部分,我們將演示如何使用此鉤子來檢查你的提交資訊是否符合要求的模式。

整個提交過程完成後,post-commit 鉤子會執行。它不接收任何引數,但你可以透過執行 git log -1 HEAD 輕鬆獲取最後一次提交。通常,此指令碼用於通知或類似目的。

電子郵件工作流鉤子

你可以為基於電子郵件的工作流設定三個客戶端鉤子。它們都由 git am 命令呼叫,因此如果你的工作流中沒有使用該命令,你可以安全地跳到下一節。如果你正在透過 git format-patch 準備的電子郵件接收補丁,那麼其中一些可能會對你有幫助。

第一個執行的鉤子是 applypatch-msg。它接收一個引數:包含提議的提交資訊的臨時檔名。如果此指令碼以非零狀態退出,Git 將中止補丁。你可以使用此鉤子確保提交資訊格式正確,或透過讓指令碼就地編輯來規範化資訊。

透過 git am 應用補丁時執行的下一個鉤子是 pre-applypatch。有點令人困惑的是,它在補丁應用之後但在提交之前執行,因此你可以使用它在提交之前檢查快照。你可以使用此指令碼執行測試或檢查工作樹。如果缺少某些內容或測試不透過,以非零狀態退出將中止 git am 指令碼,而不提交補丁。

git am 操作期間執行的最後一個鉤子是 post-applypatch,它在提交完成後執行。你可以使用它來通知一個組或你拉取的補丁的作者你已完成此操作。你不能用此指令碼停止補丁過程。

其他客戶端鉤子

pre-rebase 鉤子在你執行任何 rebase 操作之前執行,並可以透過以非零狀態退出中止該過程。你可以使用此鉤子來禁止 rebase 任何已經推送的提交。Git 安裝的示例 pre-rebase 鉤子就是這樣做的,儘管它做出了一些可能與你的工作流不符的假設。

post-rewrite 鉤子由替換提交的命令執行,例如 git commit --amendgit rebase(但不包括 git filter-branch)。它的唯一引數是哪個命令觸發了重寫,並且它透過 stdin 接收重寫列表。此鉤子具有與 post-checkoutpost-merge 鉤子許多相同的用途。

成功執行 git checkout 後,post-checkout 鉤子會執行;你可以使用它為你的專案環境正確設定工作目錄。這可能意味著移動你不希望版本控制的大型二進位制檔案、自動生成文件或類似的操作。

post-merge 鉤子在成功的 merge 命令後執行。你可以使用它來恢復 Git 無法跟蹤的工作樹中的資料,例如許可權資料。此鉤子同樣可以驗證 Git 控制之外的檔案是否存在,你可能希望在工作樹更改時將其複製進來。

pre-push 鉤子在 git push 期間執行,在遠端引用更新之後但在任何物件傳輸之前。它接收遠端名稱和位置作為引數,並接收透過 stdin 傳遞的待更新引用列表。你可以使用它在推送發生之前驗證一組引用更新(非零退出程式碼將中止推送)。

Git 作為其正常操作的一部分,偶爾會透過呼叫 git gc --auto 進行垃圾回收。pre-auto-gc 鉤子在垃圾回收發生之前被呼叫,可用於通知你正在發生此操作,或者在不合適的時候中止回收。

伺服器端鉤子

除了客戶端鉤子,作為系統管理員,你還可以使用幾個重要的伺服器端鉤子來為你的專案強制執行幾乎任何型別的策略。這些指令碼在推送到伺服器之前和之後執行。pre 鉤子可以隨時以非零狀態退出以拒絕推送,並向客戶端列印錯誤訊息;你可以設定一個你希望的任意複雜的推送策略。

pre-receive

處理來自客戶端的推送時執行的第一個指令碼是 pre-receive。它接收從標準輸入推入的引用列表;如果它以非零狀態退出,則所有引用都不會被接受。你可以使用此鉤子來做諸如確保所有更新的引用都不是非快進式引用,或者對所有引用及其透過推送修改的檔案進行訪問控制。

update

update 指令碼與 pre-receive 指令碼非常相似,不同之處在於它為推送者嘗試更新的每個分支執行一次。如果推送者嘗試推送到多個分支,pre-receive 只執行一次,而 update 為每個他們正在推送的分支執行一次。此指令碼不從標準輸入讀取,而是接收三個引數:引用(分支)的名稱、推送前該引用指向的 SHA-1 值,以及使用者嘗試推送的 SHA-1 值。如果 update 指令碼以非零狀態退出,則只有該引用被拒絕;其他引用仍然可以更新。

post-receive

post-receive 鉤子在整個過程完成後執行,可用於更新其他服務或通知使用者。它接收與 pre-receive 鉤子相同的標準輸入資料。示例包括向列表傳送電子郵件、通知持續整合伺服器或更新工單跟蹤系統——你甚至可以解析提交資訊,檢視是否有任何工單需要開啟、修改或關閉。此指令碼無法停止推送過程,但客戶端在它完成之前不會斷開連線,因此如果你嘗試執行任何可能需要很長時間的操作,請務必小心。

提示

如果你正在編寫一個其他人需要閱讀的指令碼/鉤子,請優先使用命令列引數的完整版本;六個月後你就會感謝我們了。

scroll-to-top