你好,我是小桔,是一個沒有感情的代碼崽。前端
今天給你們介紹一下 Git Hooks,相信 Git 你們都在用吧,Git 除了用做版本控制,還有許多高級功能,Git Hooks 就是其中之一。react
> 本文環境: > > - Git 版本:2.27.0 > - Husky 版本:4.2.5 > - Node.js 版本:12.16.2webpack
前言
作過前端的同窗對 Hook 這個東西應該很瞭解吧,後端也是有 Hook 這種概念的,好比 Java 的@PostConstruct
,也是一種 Hook 的體現。簡單來講,Hook 就是在執行某個事件以前或以後進行一些其餘額外的操做。git
舉個栗子,張三如今要吃飯,那麼吃飯就是一個事件,吃飯前和吃飯後就能夠稱爲兩個鉤子。如今你想讓張三在吃飯前洗下手,那麼咱們就能夠在吃飯前這個鉤子這裏,設置一個洗手的動做。張三在每次吃飯前,都會檢查一下這個鉤子,有什麼要作的,都會照作。這樣,就實現了咱們的需求。github
Git 也是如此,在 Git 中也有許多的事件(commit、push 等等),每一個事件也是對應了有不一樣的鉤子的(如 commit 前,commit 後),那麼咱們就能夠在這些鉤子這裏配置一些本身須要執行的操做來實現各類各樣的需求。web
使用
真實場景
可能初次瞭解 Git Hooks 的同窗會有一些疑問:這個東西到底能幹嗎?我之前沒用過它不也同樣好好的嗎?我幹嗎要用它?shell
其實這說得很對,**任何技術都是有需求採用,沒有需求就別去硬塞,永遠記住:技術爲業務服務。**可是這並不妨礙你先去了解它,畢竟,只有你先知道了這項技術能解決什麼樣的問題,往後當你遇到相應的問題時,你才知道該用什麼技術去解決。npm
這裏我給出一個真實的場景,是咱們團隊在開發 Lin UI 的時候遇到的:json
咱們的 Git 倉庫中包含了編譯後的代碼,因此每次修改了源碼,都須要運行一下編譯命令,而後把源碼和編譯後的代碼一塊兒提交到 Git 倉庫,這個流程沒什麼問題。可是,人腦不是電腦,總會有疏忽的時候,常常會出現這樣一種狀況:修改了源碼,卻忘記了運行編譯命令,最後只把源碼提交到了 Git 倉庫,致使線上倉庫的源碼和編譯產物不一致、後端
這個問題雖然不是特別嚴重,但總是出現也總歸很差。因此咱們就想了一個辦法,再也不手動編譯,把編譯任務交給 CI 去作,這樣就不存在這樣的問題。
但事情老是沒那麼順利,由於咱們在本地開發調試的時候是須要編譯代碼的,因此就會生成一部分編譯代碼,在使用 Git 時,咱們常常會使用git add .
命令,會把全部修改了的代碼都提交到倉庫,這顯示是不行的。由於如今咱們已經把編譯交給 CI 去作了,而且爲了 Code Review 方便,編譯代碼不該該再提交到倉庫了。若是每次手動去把編譯代碼去除,又很是麻煩,那該怎麼辦呢?
這種狀況,就可使用 Git Hooks 幫咱們在每次提交前自動把編譯代碼去掉了。
> PS:這個場景雖然不那麼常見和通用,但確實是在開發中真實碰見的。
Git Hooks 介紹
Git Hooks 的實現其實很是簡單,就是就.git/hooks
文件下,保存了一些 shell 腳本,而後在對應的鉤子中執行這些腳本就好了。好比下圖中,這是一個尚未配置 Git Hooks 的倉庫,默認會有不少.sample
結尾的文件,這些都是示例文件
咱們打開pre-commit.sample
文件看一下其中的內容,大體意思是說這是一個示例,作了一些格式方面的檢測,這個腳本默認是不生效的,若是要生效,把文件名改成pre-commit.sample
便可
pre-commit
這個鉤子是在git commit
命令執行以前觸發
Git 支持的全部鉤子見下表(加粗的爲經常使用鉤子):
Git Hook | 調用時機 | 說明 |
---|---|---|
pre-applypatch | git am 執行前 |
|
applypatch-msg | git am 執行前 |
|
post-applypatch | git am 執行後 |
不影響git am 的結果 |
pre-commit | git commit 執行前 |
能夠用git commit --no-verify 繞過 |
commit-msg | git commit 執行前 |
能夠用git commit --no-verify 繞過 |
post-commit | git commit 執行後 |
不影響git commit 的結果 |
pre-merge-commit | git merge 執行前 |
能夠用git merge --no-verify 繞過。 |
prepare-commit-msg | git commit 執行後,編輯器打開以前 |
|
pre-rebase | git rebase 執行前 |
|
post-checkout | git checkout 或git switch 執行後 |
若是不使用--no-checkout 參數,則在git clone 以後也會執行。 |
post-merge | git commit 執行後 |
在執行git pull 時也會被調用 |
pre-push | git push 執行前 |
|
pre-receive | git-receive-pack 執行前 |
|
update | ||
post-receive | git-receive-pack 執行後 |
不影響git-receive-pack 的結果 |
post-update | 當 git-receive-pack 對 git push 做出反應並更新倉庫中的引用時 |
|
push-to-checkout | 當``git-receive-pack對 git push作出反應並更新倉庫中的引用時,以及當推送試圖更新當前被簽出的分支且 receive.denyCurrentBranch配置被設置爲 updateInstead`時 |
|
pre-auto-gc | git gc --auto 執行前 |
|
post-rewrite | 執行git commit --amend 或git rebase 時 |
|
sendemail-validate | git send-email 執行前 |
|
fsmonitor-watchman | 配置core.fsmonitor 被設置爲.git/hooks/fsmonitor-watchman 或.git/hooks/fsmonitor-watchmanv2 時 |
|
p4-pre-submit | git-p4 submit 執行前 |
能夠用git-p4 submit --no-verify 繞過 |
p4-prepare-changelist | git-p4 submit 執行後,編輯器啓動前 |
能夠用git-p4 submit --no-verify 繞過 |
p4-changelist | git-p4 submit 執行並編輯完changelist message 後 |
能夠用git-p4 submit --no-verify 繞過 |
p4-post-changelist | git-p4 submit 執行後 |
|
post-index-change | 索引被寫入到read-cache.c do_write_locked_index 後 |
PS:完整鉤子說明,請參考官網連接
Husky 配置
從上面的介紹中,咱們知道 Git Hook 保存在 .git 文件夾中。不知你有沒有發現這會有一個問題?可能細心的同窗已經知道了,Git 是一個多人協做工具,那按理說 Git 倉庫中的全部文件都應該被跟蹤而且上傳至遠程倉庫的。可是有個例外,.git
文件夾不會,這就致使一個問題,咱們在本地配置好 Git Hook 後,怎麼分享給其餘小夥伴兒呢?copy 嗎?那未免太 low 了,都用 Git 了,還 copy,也太不優雅了。這時候,就輪到 Husky 出場了。
Husky 是一個讓配置 Git 鉤子變得更簡單的工具(題外話:Husky 是哈士奇的意思,我猜多是做者養了條二哈)
下面這些流行的項目都在使用 Husky,可見它確實是一個很是好用的工具:
Husky 的原理是讓咱們在項目根目錄中寫一個配置文件,而後在安裝 Husky的時候把配置文件和 Git Hook 關聯起來,這樣咱們就能在團隊中使用 Git Hook 了。
下面開始配置 Husky
第一步
使用 npm 初始化你的項目(若是項目已有 package.json,請跳至第二步)
npm init -y
第二步
安裝 Husky
// 注意 Node.js 版本要 >=10 npm install husky -D
第三步
書寫配置文件,4.2.5 版本的 Husky 共支持如下幾種格式的配置文件:
- .huskyrc
- .huskyrc.json
- .huskyrc.yaml
- .huskyrc.yml
- .huskyrc.js
- husky.config.js
我的習慣,這裏我採用的是.huskyrc
,在其中書寫 json 格式的配置,以下:
{ "hooks": { "pre-commit": "git restore -W -S dist examples/dist" } }
是否是很簡單,咱們來解讀一下這個配置文件。hooks
這個對象中,key 就是鉤子名,而 value 就是須要執行的命令。上面這個配置的含義就是,在每次執行 git commit
以前,都會把dist
和examples/dit
目錄下的修改回滾(這兩個目錄就是編譯產生的代碼),就不用擔憂誤把編譯後的代碼提交到倉庫中了。
上面咱們只寫了一條命令,若是想執行兩條命令怎麼辦呢?好比我還想在git commit
以前用 EsLint 檢查一下代碼質量,咱們能夠像下面這樣寫:
{ "hooks": { "pre-commit": "git restore -W -S dist examples/dist && eslint ." } }
是的,就是這麼簡單。若是 EsLint 檢測不經過,那麼git commit
是會被阻止的,就不用擔憂"垃圾代碼"被提交到線上倉庫了。
Husky 注意事項
Husky 讓咱們能夠很方便的配置 Git Hooks,同時,也提供了一些實用方便的小技巧以及一些咱們須要注意的點
不支持的鉤子
Husky 不支持服務端 Git 的鉤子:
- pre-receive
- update
- post-receive
跳過全部鉤子
有時你可能不想運行鉤子,那麼能夠像下面這樣跳過:
HUSKY_SKIP_HOOKS=1 git rebase ...
禁用自動安裝
若是你不想 Husky 爲你自動安裝鉤子(好比 clone 了一個第三方的庫,想要本身開發時),能夠這樣作:
HUSKY_SKIP_INSTALL=1 npm install
最後
本文介紹了 Git Hooks 具體有哪些,並講解了如何用 Husky 便捷的配置 Git Hook。下一篇文章,我會教你如何用 commitlint 結合 Husky 來規範團隊的 commit 信息,若是有興趣的話,記得必定要關注我哦!
我是小桔,歡迎關注個人微信公衆號,帶你瞭解更多先後端知識。