git是現在主流的版控控制,寫軟體的人基本上都知道,但關於如何優化工作流以及什麼是git hooks知道的人可能就不多,因為這個部分是一種「優化」,使用了會更好,但是不用也沒關係,那我研究後覺得git hooks學會之後好處很多,那下面會儘量用好懂的方式來記錄跟介紹。

不講腳本寫法,不講複雜應用,只講整體的概念以及簡單的小應用來幫助理解概念。
但還是要有對於git的簡單知識,不然可能看不懂這篇。

這篇文章主要會有以下這三個大重點:

  • 什麼是git hooks
  • 為什麼要使用git hooks
  • git hook基本的應用有哪些

什麼是git hooks

用一句話來講解這個概念,就是「每次使用了git的資料庫中發生特別事件時(像生命週期)自動運行的腳本」。

生命週期就是像人的一生中,有嬰兒、壯年,生、老、病、死,那git的特別事件我覺得也像是生命週期一樣,就是git的一些重要環節上代表各個git的生命週期,這個稍微就會解釋。

腳本就是一種程式的文件,我會把它想像是可以做某一種事情的程式,像是玩遊戲的時候,假如覺得一直在做一些重複性的事情很煩,那就可以寫一個滑鼠自動一直點的腳本。

而使用了git的資料庫的話,就是一個乾淨的專案裡面,只要下一個指令git init,那這個專案就會被加入到git的版控中,然後專案目錄下也會多出一個.git的隱藏檔。

好,然後下一個問題我想就是那該如何去之後這個腳本會怎麼運行? 我得去哪裡控制它?

首先,會在它git專屬的隱藏檔裡面,在.git/hooks的位置,可以在裡面去放入腳本來去進行控制的動作,但要注意,一般來說是觀測不到的,因為git的.git隱藏檔是預設看不到,所以要使用git hooks的技術,第一步得先找到git hooks檔案所需要放置的位置。

以下是打開git隱藏檔,找出git hooks的方式,我是用vscode,所以只講它的情境:


一開始打開vscode,

=> 設定 (右下角齒輪裡面,蠻明顯的,按下去再使用者那邊找)

=> 找Files: Exclude

=> 如上圖,刪除裡面.git選項

這樣一來,你就會發現隱藏檔露出了它的廬山真面目,但注意的是,因為這種改動從設定(使用者)的話是影響整個專案,而之所以git隱藏檔要隱藏起來,是因為不小心亂改到是很危險的,所以如果用這種方式改的話,那之後所有的專案都可以看到的。

這邊也提供另外一個技巧,如果你今天只想for自己的這個專案可以看到的git隱藏檔,可以這樣做。

一樣進到設定,但不是使用者,而是它右邊的工作區,點擊進去工作區之中的settings.json,加上這一段程式碼就ok了。

1
2
3
4
5
{
"files.exclude":{
"**/.git": false,
}
}

當成功的把git的隱藏檔顯露出來後,就可以觀測到git hooks的所在。

一個名字叫做hooks的資料夾,裡面擺了很多的git生命週期事件的檔案,等等會把這個檔案跟git的真正對應指令做個比較圖,先講這邊要如何去修改跟撰寫。

其實很簡單,就是把這個檔案的sample給刪除,直接去更改裡面就會生效了,我的理解是sample是要讓它預設為沒作用,那拿掉就變成有作用。

另外裡面打開會長這個,除了最上面的#!/bin/sh之外其他都刪除也沒關係,我都會先把預設的都刪掉然後再自己寫新的,還有就是裡面寫的腳本可以用任何的程式語言去寫,像是node.js也是完全沒問題。

接下來這邊最後就來講裡面的各種檔案對應的git指令吧:

有很多,但我只列舉git的最常用的那幾個,像是耳熟能詳的git addgit commit這種,而我們想要利用git hooks做的事情,其實就是當我們在使用這些git指令的時候,可以在那個時期做事情而已,也就是執行腳本。

會發現hit hooks裡面的特定檔案事件會把git指令分成執行前以及執行後,初看會覺得似乎沒有必要,但這卻是必須的。

我來舉例一個情境,假如你使用腳本,是為了在git commit之前去做檢查,要是commit訊息中,沒有某些字,你要用git hooks腳本的方式,阻止coomit訊息的發送,那麼同樣的腳本,執行前跟執行後就分成兩種不同的情境。

git commit執行之前的話,那代表還沒有成功commit,所以腳本檢查完去阻止,是可以成功擋下的,
但是在git commit執行之後的話,它git生命週期的點已經是commit結束之後了,就算可以檢查得出錯誤,但也沒辦法阻止發生,這是它一個很大的差別。

所以說,執行前有它的情境,執行後也有它的用處,這是兩種不同的卻又都有需求,兩個都要有很合理。

為什麼要使用git hooks

關於這個部分,我有整理出了幾點:

  1. 自動化流程
  2. 強制規範
  3. 安全性

第一,自動化流程的意思是使用Git hooks可以自動化許多重複性、瑣碎的工作。

沒有也可以,但你就是要手動一直做很多重複事情,軟體開發時總是會遇到這種事情,像是運行單元測試、檢查代碼風格、自動化部署等等,會發現這些事情可能超級耗時間,而且因為是手動去執行的,所以會發生一些像是忘記執行,或是少執行了一些步驟,然後導致整個在使用版控的流程發生錯誤。

git hooks只要把這個自動化的流程流程寫成腳本,放進去git的生命週期,像是每次push之後都要做一個自動化部署,直接幫你省一大堆時間,開發效率直線上升。

接著是強制規範的部分,Git hooks可以強制做一些規範,像是說查程式碼風格、檢查文件格式、防止不必要的合併等等,甚至連git commit訊息都可以去規定它要怎麼寫,用了就回不去了,實在是太方便。

這樣做可以確保假如有在協作的話,大家全部人的風格都符合同一個標準,有一致性的同時也拉高了可讀性,讓寫code變成更愉快的同時,程式碼也是變的用容易維護以及修改。

最後是安全性,Git hooks可以幫助保持資料庫的安全性,例如說防止提交敏感資訊、防止執行有害的程式碼等等。

像是如果有不能被傳上去的禁止字樣,或是可怕的程式碼寫法,直接上傳上去是會造成困擾的,這個部分跟強制規範規範其實有點類似,主要就是在提交程式碼之前,再次做個檢查,看看這些程式中有沒有包含危險不安全的東西存在,有的話就馬上警告,確保整個專案都是安全的狀態。

總之,做個小結論,使用Git hook可以幫助自動化流程、強制規範和提高安全性,從而提高開發效率、確保品質和減少風險,不用可以,用了會更好,這是我覺得它的優點。

git hook基本的應用有哪些

這邊最基礎的話,從pre-commit開始寫起git hooks,也就是所謂的git commit執行之前的腳本,跟前面說的一樣,除了最上面那行之外,其他全部刪掉,自己寫。

我這邊寫的意思是,當coomit的指令下出去,指令之後,執行之前會去跑這個腳本觸發,功能是會呼叫一次我的名字,”hello vic”這樣。

有用到了兩個我覺得要知道的語法,介紹一下什麼是Echoexit

Echo命令用來將後方參數輸出到console,就是把寫的東西印出來。
exit命令如果是0的話會讓commit繼續,若exit後為非0,例如exit 1則會終止commit。

然後是稍微讓大家了解概念的應用,也就是執行腳本這件事情,專案當中,可能就已經使用了很多lint系列的套件,這些套件就是專門用來負責處理程式的格式、風格,所以其實可以把它們直接加上git hooks就好了。

舉例來說,假如專案中有在使用eslint,通常Node.js專案會在package.json的scripts欄位下設定lint腳本,來呼叫lint工具去檢查JavaScript等程式碼的語法。

那我可以把它搭配做使用,在git hooks當中的pre-commit腳本中去執行npm run lint。

這樣就會達成效果是commit指令下去之後,會在commit執行之前,幫我得程式碼做一個檢查的動作,這也是我目前比較常用的做法,然後commit的話也有專門的commitlint可以做使用,所以其實不用真的會寫git hooks的腳本也沒關係。

小結

以上大致就是我在研究git hooks之後,想分享及做的筆記心得,下次可能會想研究git hooks的工具搭配,因為其實要打開隱藏檔這件事情真的是比較麻煩的,而且由於.git隱藏檔不吃版控的關係,我找了一些奇怪的方式才能追蹤到推遠端,覺得應該可以用更好的方式。

有一個叫做Husky的工具,據說使用它可以讓git hooks這件事情變得更加簡單,下一個研究的目標就會是它,研究完我會再把我的心得研究丟blog。

參考資料

影片類

(2) [Git#8] 用pre-commit檢查提交時的分支是否正確 - YouTube
透過工具建立有規範的 git commit message 吧 - YouTube

文章類

Git - Git 鉤子
菜鳥工程師 肉豬: Git 什麼是Git Hooks?
aitemr/awesome-git-hooks: 😎 A collection of awesome Git Hooks
手写 git hooks 脚本(pre-commit、commit-msg)
探索藏在Git當中的Git Hook - HackMD
如何在執行git commit前自動進行檢查?Git Hooks的基本用法 | MagicLen