--- tags: git, ci title: 探索藏在Git當中的Git Hook description: 研究Git Hook在CI的應用 author: Frank --- # 探索藏在Git當中的Git Hook [](https://gitlab.com/s716134/githook-demo/-/commits/githook/) 如果希望在git生命週期中,在本機增加一些CI[^CI]任務的話,或許可以不必特地架一台CI Server[^CI_SERVER]去處理,只需要使用到本篇的主角「Git Hook」,就可以達到基本的CI任務了。 [TOC] ## 1. 什麼是Git Hook? Git提供的一組客製化條件觸發腳本的規則,統稱這個規則為Git Hook。這些規則適用於Git的幾個重要操作環節,例如: 提交(commit)、合併(merge)等[^CUSTOMIZING_GIT]。 * 提交流程觸發(Committing-Workflow Hooks) * 郵件流程觸發(Email Workflow Hooks) * 其它客戶端觸發(Other Client Hooks) * 伺服器端觸發(Server-Side Hooks) :::warning :warning: 為了聚焦在本文所探討的議題上,所以僅會介紹幾個基本的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...),相信不僅方便留存測試紀錄,並且可以節省許多繁複的操作。 :::info :bulb: Git Hook腳本可以使用任何程式語言去編寫,常見的例如: Shell、Ruby、Perl或Python等。 ::: ## 4. 我該在哪裡使用Git Hook? 一般來說,Git在初始化專案的時候,會自動產生一組Git Hook範例腳本,並將其存放在`.git/hooks/`底下。~~幸運的話~~可以在`.git/hooks/`底下看到下面這些範例Git Hook腳本: ```bash= 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的目錄[^SHARE]。 :::info :bulb: 只有最開始使用`git init`初始化的資料夾當中,會出現這些範例Git Hook腳本。這其實是因為`.git/`內的檔案,並不會被Git主動納入版本控管。 ::: ## 5. 哪些時機可以觸發Git Hook? ### 5.1 使用`pre-commit`讓顯示訊息一致 :::danger **案例描述 :** 因為會在不同的電腦、工具中,對相同專案使用Commit紀錄修改,有時候會忘記自己使用哪個名字、信箱,所以時常導致在同一個專案出現多名角色。  ::: :::success **解決方法[^CASE1] :** 利用簡單的Shell Script判斷使用者資訊,沒有設定好就不給Commit。 ```bash= #!/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`觸發執行回歸測試 :::danger **案例描述 :** 因為專案的急迫性,有時候開發完新功能或是修改完BUG後,就會急急忙忙地將程式推上版。但是,若是組織沒有一個完善的CI Server,且自己也忘記在推版前執行測試案例,去確認原有功能在修改後是否保持完整,那很可能就會不小心推了一版「改A壞B」的程式上去。  ::: :::success **解決方法[^CASE2] :** ```bash= #!/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 ``` ::: <!-- ### 5.2 使用`pre-push`或`post-merge`觸發Docker打包Image :::danger **案例描述 :** ::: :::success **解決方法[^CASE3] :** ```bash= ::: --> :::warning :warning: 實際上觸發Git Hook不止這些時機[^TASKS][^TASKS2],這裡僅是把個人比較熟悉的場景列上來。 ::: ## 6. 故障排除 ### 6.1 hook was ignored because it's not set as executable 若是出現這個訊息,代表commiter並沒有執行`.git/hooks/`的權限,這時就可以使用`chmod ug+x .git/hooks/*`這行指令,給予使用者及群組擁有`執行(x)`的權限。 [^CI]: [What is Continuous Integration?](https://www.atlassian.com/continuous-delivery/continuous-integration) [^CI_SERVER]: [為什麼我們需要CI Server?](https://ithelp.ithome.com.tw/articles/10102375) [^CUSTOMIZING_GIT]: [Customizing Git - Git Hooks](https://git-scm.com/book/zh-tw/v2/Customizing-Git-Git-Hooks) [^SHARE]: [How to Share Git Hooks with the Team](https://chamikakasun.medium.com/how-to-share-git-hooks-with-the-team-37424603dd91) [^CASE1]: 不可考,突然找不到來源,待補上 [^CASE2]: [mallocator/git.hook.mvn_clean](https://gist.github.com/mallocator/34332f7a6a68d15a419c) [^CASE3]: [Using a post-merge git hook to clean up old branches](https://www.liquidlight.co.uk/blog/using-a-post-merge-git-hook-to-clean-up-old-branches/) [^TASKS]: [Understanding Git Hooks](https://codeburst.io/understanding-git-hooks-in-the-easiest-way-bad9afcbb1b3) [^TASKS2]: [What hooks are supported by GitKraken?](https://support.gitkraken.com/working-with-repositories/githooks/)
×
Sign in
Email
Password
Forgot password
or
Sign in via Google
Sign in via Facebook
Sign in via X(Twitter)
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
Continue with a different method
New to HackMD?
Sign up
By signing in, you agree to our
terms of service
.