Try   HackMD

探索藏在Git當中的Git Hook

如果希望在git生命週期中,在本機增加一些CI[1]任務的話,或許可以不必特地架一台CI Server[2]去處理,只需要使用到本篇的主角「Git Hook」,就可以達到基本的CI任務了。

1. 什麼是Git Hook?

Git提供的一組客製化條件觸發腳本的規則,統稱這個規則為Git Hook。這些規則適用於Git的幾個重要操作環節,例如: 提交(commit)、合併(merge)等[3]

  • 提交流程觸發(Committing-Workflow Hooks)
  • 郵件流程觸發(Email Workflow Hooks)
  • 其它客戶端觸發(Other Client Hooks)
  • 伺服器端觸發(Server-Side Hooks)

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
為了聚焦在本文所探討的議題上,所以僅會介紹幾個基本的Committing的自定義Git Hook。

2. 為什麼需要Git Hook?

在講求快速開發的時代,軟體提交的數量也隨之大量增加。若還是寄望所有的CI工作都交由CI Server來處理,那很快就會面臨到機器效能不足的嚴峻議題。另一方面,組織也希望減少在CI上的成本,同時又期許軟體產出的品質提升。事實上,我認為「許多的CI工作,是可以分派給開發人員自己負責,而不是完全將其推卸給其它人或機器」。Git Hook則是我認為目前在現代開發模式中,最適合拿來利用、推廣的一項工具。

3. 哪些人會需要使用到Git Hook?

  • 開發人員
    正如先前所提到,使用Git Hook來達到基礎的CI任務,可以讓開發人員可以對自己交付的Source Code負責任。除此之外,只要定義好處發腳本的場景,開發人員並不需要額外再特別去學一套新的工具、語言。
  • 測試人員
    測試人員如果可以定義好哪些Git場景(commit、push)去觸發執行哪些測試工具、案例(JUnit、JMeter),相信不僅方便留存測試紀錄,並且可以節省許多繁複的操作。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
Git Hook腳本可以使用任何程式語言去編寫,常見的例如: Shell、Ruby、Perl或Python等。

4. 我該在哪裡使用Git Hook?

一般來說,Git在初始化專案的時候,會自動產生一組Git Hook範例腳本,並將其存放在.git/hooks/底下。幸運的話可以在.git/hooks/底下看到下面這些範例Git Hook腳本:

applypatch-msg.sample pre-applypatch.sample pre-rebase.sample commit-msg.sample pre-commit.sample pre-receive.sample fsmonitor-watchman.sample pre-merge-commit.sample prepare-commit-msg.sample post-update.sample pre-push.sample update.sample

對Git而言,僅會認hooks底下符合這些命名規範的檔案名稱,且不需要任何副檔名。所以這些腳本預設是關閉的,如果要啟用它們,僅需要重新命名將.sample移除即可。如果要固定使用同一組Git Hook腳本,可以透過core.hooksPath來指向執行Git Hook的目錄[4]

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
只有最開始使用git init初始化的資料夾當中,會出現這些範例Git Hook腳本。這其實是因為.git/內的檔案,並不會被Git主動納入版本控管。

5. 哪些時機可以觸發Git Hook?

5.1 使用pre-commit讓顯示訊息一致

案例描述 :
因為會在不同的電腦、工具中,對相同專案使用Commit紀錄修改,有時候會忘記自己使用哪個名字、信箱,所以時常導致在同一個專案出現多名角色。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

解決方法[5] :
利用簡單的Shell Script判斷使用者資訊,沒有設定好就不給Commit。

#!/bin/sh username=$(git config user.name) if [ "$username" != "LAI, CHUN JING" ] then cat <<\EOF [ERROR] Are you LAI, CHUN JING?" EOF exit 1 fi

5.2 使用pre-push觸發執行回歸測試

案例描述 :
因為專案的急迫性,有時候開發完新功能或是修改完BUG後,就會急急忙忙地將程式推上版。但是,若是組織沒有一個完善的CI Server,且自己也忘記在推版前執行測試案例,去確認原有功能在修改後是否保持完整,那很可能就會不小心推了一版「改A壞B」的程式上去。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

解決方法[6] :

#!/bin/sh echo "Running mvn clean test for errors" DIR=`pwd` CWD="$DIR/app_example" MAIN_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" cd $CWD MVN_RESULT=$(mvn clean test 2>&1) if [ $? -ne 0 ]; then echo echo "${MVN_RESULT}" | ((tee /dev/fd/5 | grep -A 10 -B 2 "Reactor Summary:" >/dev/fd/4) 5>&1 | sed -n -e '/^Failed tests:/,/Tests run:.*$/ p' ) 4>&1 echo echo "Error while testing the code" cd $CWD exit 1 fi

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
實際上觸發Git Hook不止這些時機[7][8],這裡僅是把個人比較熟悉的場景列上來。

6. 故障排除

6.1 hook was ignored because it's not set as executable

若是出現這個訊息,代表commiter並沒有執行.git/hooks/的權限,這時就可以使用chmod ug+x .git/hooks/*這行指令,給予使用者及群組擁有執行(x)的權限。


  1. What is Continuous Integration? ↩︎

  2. 為什麼我們需要CI Server? ↩︎

  3. Customizing Git - Git Hooks ↩︎

  4. How to Share Git Hooks with the Team ↩︎

  5. 不可考,突然找不到來源,待補上 ↩︎

  6. mallocator/git.hook.mvn_clean ↩︎

  7. Understanding Git Hooks ↩︎

  8. What hooks are supported by GitKraken? ↩︎