Git 鉤子 (自動部署)
Git 鉤子
和其它版本控制系統一樣,Git 能在特定的重要動作發生時觸發自定義指令碼。 有兩組這樣的鉤子:客戶端的和伺服器端的。 客戶端鉤子由諸如提交和合並這樣的操作所呼叫,而伺服器端鉤子作用於諸如接收被推送的提交這樣的聯網操作。 你可以隨心所欲地運用這些鉤子。
安裝一個鉤子
鉤子都被儲存在 Git 目錄下的 hooks
子目錄中。 也即絕大部分專案中的 .git/hooks
。 當你用 git init
初始化一個新版本庫時,Git 預設會在這個目錄中放置一些示例指令碼。這些指令碼除了本身可以被呼叫外,它們還透露了被觸發時所傳入的引數。 所有的示例都是 shell 指令碼,其中一些還混雜了 Perl 程式碼,不過,任何正確命名的可執行指令碼都可以正常使用 —— 你可以用 Ruby 或 Python,或其它語言編寫它們。 這些示例的名字都是以 .sample
把一個正確命名且可執行的檔案放入 Git 目錄下的 hooks
子目錄中,即可啟用該鉤子指令碼。 這樣一來,它就能被 Git 呼叫。 接下來,我們會講解常用的鉤子指令碼型別。
客戶端鉤子
客戶端鉤子分為很多種。 下面把它們分為:提交工作流鉤子、電子郵件工作流鉤子和其它鉤子。
Note |
需要注意的是,克隆某個版本庫時,它的客戶端鉤子 並不 隨同複製。 如果需要靠這些指令碼來強制維持某種策略,建議你在伺服器端實現這一功能。(請參照 使用強制策略的一個例子 中的例子。) |
提交工作流鉤子
前四個鉤子涉及提交的過程。
pre-commit
鉤子在鍵入提交資訊前執行。 它用於檢查即將提交的快照,例如,檢查是否有所遺漏,確保測試執行,以及核查程式碼。 如果該鉤子以非零值退出,Git 將放棄此次提交,不過你可以用 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
的執行,這樣補丁就不會被提交。
post-applypatch
運行於提交產生之後,是在 git am
執行期間最後被呼叫的鉤子。 你可以用它把結果通知給一個小組或所拉取的補丁的作者。 但你沒辦法用它停止打補丁的過程。
其它客戶端鉤子
pre-rebase
鉤子運行於變基之前,以非零值退出可以中止變基的過程。 你可以使用這個鉤子來禁止對已經推送的提交變基。 Git 自帶的 pre-rebase
鉤子示例就是這麼做的,不過它所做的一些假設可能與你的工作流程不匹配。
post-rewrite
鉤子被那些會替換提交記錄的命令呼叫,比如 git commit --amend
和 git rebase
(不過不包括 git filter-branch
)。 它唯一的引數是觸發重寫的命令名,同時從標準輸入中接受一系列重寫的提交記錄。 這個鉤子的用途很大程度上跟 post-checkout
和 post-merge
差不多。
在 git checkout
成功執行後,post-checkout
鉤子會被呼叫。你可以根據你的專案環境用它調整你的工作目錄。 其中包括放入大的二進位制檔案、自動生成文件或進行其他類似這樣的操作。
在 git merge
成功執行後,post-merge
鉤子會被呼叫。 你可以用它恢復 Git 無法跟蹤的工作區資料,比如許可權資料。 這個鉤子也可以用來驗證某些在 Git 控制之外的檔案是否存在,這樣你就能在工作區改變時,把這些檔案複製進來。
pre-push
鉤子會在 git push
執行期間, 更新了遠端引用但尚未傳送物件時被呼叫。 它接受遠端分支的名字和位置作為引數,同時從標準輸入中讀取一系列待更新的引用。 你可以在推送開始之前,用它驗證對引用的更新操作(一個非零的退出碼將終止推送過程)。
Git 的一些日常操作在執行時,偶爾會呼叫 git gc --auto
進行垃圾回收。 pre-auto-gc
鉤子會在垃圾回收開始之前被呼叫,可以用它來提醒你現在要回收垃圾了,或者依情形判斷是否要中斷回收。
伺服器端鉤子
除了客戶端鉤子,作為系統管理員,你還可以使用若干伺服器端的鉤子對專案強制執行各種型別的策略。 這些鉤子指令碼在推送到伺服器之前和之後執行。 推送到伺服器前執行的鉤子可以在任何時候以非零值退出,拒絕推送並給客戶端返回錯誤訊息,還可以依你所想設定足夠複雜的推送策略。
pre-receive
處理來自客戶端的推送操作時,最先被呼叫的指令碼是 pre-receive
。 它從標準輸入獲取一系列被推送的引用。如果它以非零值退出,所有的推送內容都不會被接受。 你可以用這個鉤子阻止對引用進行非快進(non-fast-forward)的更新,或者對該推送所修改的所有引用和檔案進行訪問控制。
update
update
指令碼和 pre-receive
指令碼十分類似,不同之處在於它會為每一個準備更新的分支各執行一次。 假如推送者同時向多個分支推送內容,pre-receive
只執行一次,相比之下 update
則會為每一個被推送的分支各執行一次。 它不會從標準輸入讀取內容,而是接受三個引數:引用的名字(分支),推送前的引用指向的內容的 SHA-1 值,以及使用者準備推送的內容的 SHA-1 值。 如果 update 指令碼以非零值退出,只有相應的那一個引用會被拒絕;其餘的依然會被更新。
post-receive
post-receive
掛鉤在整個過程完結以後執行,可以用來更新其他系統服務或者通知使用者。 它接受與 pre-receive
相同的標準輸入資料。 它的用途包括給某個郵件列表發信,通知持續整合(continous integration)的伺服器,或者更新問題追蹤系統(ticket-tracking system) —— 甚至可以通過分析提交資訊來決定某個問題(ticket)是否應該被開啟,修改或者關閉。 該指令碼無法終止推送程序,不過客戶端在它結束執行之前將保持連線狀態,所以如果你想做其他操作需謹慎使用它,因為它將耗費你很長的一段時間。