使用husky統一管理git-hooks,實現git commit之前校驗eslint,通過才能commit成功
簡介
Git 能在特定的重要動作發生時觸發自定義指令碼,其中比較常用的有:pre-commit
、commit-msg
、pre-push
等鉤子(hooks)。我們可以在 pre-commit
觸發時進行程式碼格式驗證,在 commit-msg
觸發時對 commit 訊息和提交使用者進行驗證,在 pre-push
觸發時進行單元測試、e2e 測試等操作。
Git 在執行 git init
進行初始化時,會在 .git/hooks
目錄生成一系列的 hooks 指令碼:
從上圖可以看到每個指令碼的字尾都是以 .sample
結尾的,在這個時候,指令碼是不會自動執行的。我們需要把字尾去掉之後才會生效,即將 pre-commit.sample
pre-commit
才會起作用。
本文主要是想介紹一下如何編寫 git hooks 指令碼,並且會編寫兩個 pre-commit
、commit-msg
指令碼作為示例,幫助大家更好的理解 git hooks 指令碼。當然,在工作中還是建議使用現成的、開源的解決方案 husky。
正文
用於編寫 git hooks 的指令碼語言是沒有限制的,你可以用 nodejs
、shell
、python
、ruby
等指令碼語言,非常的靈活方便。
下面我將用 shell 語言來演示一下如何編寫 pre-commit
和 commit-msg
指令碼。另外要注意的是,在執行這些指令碼時,如果以非零的值退出程式,將會中斷 git 的提交/推送流程。所以在 hooks 指令碼中驗證訊息/程式碼不通過時,就可以用非零值進行退出,中斷 git 流程。
exit 1
複製程式碼
pre-commit
在 pre-commit
鉤子中要做的事情特別簡單,只對要提交的程式碼格式進行檢查,因此指令碼程式碼比較少:
#!/bin/sh
npm run lint
# 獲取上面指令碼的退出碼
exitCode="$?"
exit $exitCode
複製程式碼
由於我在專案中已經配置好了相關的 eslint 配置以及 npm 指令碼,因此在 pre-commit
中執行相關的 lint 命令就可以了,並且判斷一下是否正常退出。
// 在 package.json 檔案中已配置好 lint 命令
"scripts": {
"lint": "eslint --ext .js src/"
},
複製程式碼
下面看一個動圖,當代碼格式不正確的時候,進行 commit 就報錯了:
在修改程式碼格式後再進行提交,這時就不報錯了:
從動圖中可以看出,這次 commit 已正常提交了。
commit-msg
在 commit-msg
hooks 中,我們需要對 commit 訊息和使用者進行校驗。
#!/bin/sh
# 用 `` 可以將命令的輸出結果賦值給變數
# 獲取當前提交的 commit msg
commit_msg=`cat $1`
# 獲取使用者 email
email=`git config user.email`
msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
if [[ ! $commit_msg =~ $msg_re ]]
then
echo "\n不合法的 commit 訊息提交格式,請使用正確的格式:\
\nfeat: add comments\
\nfix: handle events on blur (close #28)\
\n詳情請檢視 git commit 提交規範:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md"
# 異常退出
exit 1
fi
複製程式碼
在 commit-msg
鉤子觸發時,對應的指令碼會接收到一個引數,這個引數就是 commit 訊息,通過 cat $1
獲取,並賦值給 commit_msg
變數。
驗證 commit 訊息的正則比較簡單,看程式碼即可。如果對 commit 提交規範有興趣,可以看看我另一篇文章。
對使用者許可權做判斷則比較簡單,只需要檢查使用者的郵箱或使用者名稱就可以了(假設現在只有 abc 公司的員工才有許可權提交程式碼)。
email_re="@abc\.com"
if [[ ! $email =~ $email_re ]]
then
echo "此使用者沒有許可權,具有許可權的使用者為: [email protected]"
# 異常退出
exit 1
fi
複製程式碼
下面用兩個動圖來分別演示一下校驗 commit 訊息和判斷使用者許可權的過程:
設定 git hooks 預設位置
指令碼可以正常執行只是第一步,還有一個問題是必須要解決的,那就是如何和同一專案的其他開發人員共享 git hooks 配置。因為 .git/hooks
目錄不會隨著提交一起推送到遠端倉庫。對於這個問題有兩種解決方案:第一種是模仿 husky 做一個 npm 外掛,在安裝的時候自動在 .git/hooks
目錄新增 hooks 指令碼;第二種是將 hooks 指令碼單獨寫在專案中的某個目錄,然後在該專案安裝依賴時,自動將該目錄設定為 git 的 hooks 目錄。
接下來詳細說說第二種方法的實現過程:
- 在
npm install
執行完成後,自動執行git config core.hooksPath hooks
命令。 -
git config core.hooksPath hooks
命令將 git hooks 目錄設定為專案根目錄下的 hooks 目錄。
"scripts": {
"lint": "eslint --ext .js src/",
"postinstall": "git config core.hooksPath hooks"
},
複製程式碼
踩坑
demo 原始碼在 windows 上是可以正常執行的,後來換成 mac 之後就不行了,提交時報錯:
hint: The 'hooks/pre-commit' hook was ignored because it's not set as executable.
複製程式碼
原因是 hooks 指令碼預設為不可執行,所以需要將它設為可執行:
chmod 700 hooks/*
複製程式碼
為了避免每次克隆專案都得修改,最好將這個命令在 npm 指令碼上加上:
"scripts": {
"lint": "eslint --ext .js src/",
"postinstall": "git config core.hooksPath hooks && chmod 700 hooks/*"
},
複製程式碼
當然,如果是 windows 就不用加後半段程式碼了。
nodejs hooks 指令碼
為了幫助前端同學更好的理解 git hooks 指令碼,我用 nodejs 又重寫了一版。
pre-commit
#!/usr/bin/env node
const childProcess = require('child_process');
try {
childProcess.execSync('npm run lint');
} catch (error) {
console.log(error.stdout.toString());
process.exit(1);
}
複製程式碼
commit-msg
#!/usr/bin/env node
const childProcess = require('child_process');
const fs = require('fs');
const email = childProcess.execSync('git config user.email').toString().trim();
const msg = fs.readFileSync(process.argv[2], 'utf-8').trim(); // 索引 2 對應的 commit 訊息檔案
const commitRE = /^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}/;
if (!commitRE.test(msg)) {
console.log();
console.error('不合法的 commit 訊息格式,請使用正確的提交格式:');
console.error('feat: add \'comments\' option');
console.error('fix: handle events on blur (close #28)');
console.error('詳情請檢視 git commit 提交規範:https://github.com/woai3c/Front-end-articles/blob/master/git%20commit%20style.md。');
process.exit(1);
}
if (!/@qq\.com$/.test(email)) {
console.error('此使用者沒有許可權,具有許可權的使用者為: [email protected]');
process.exit(1);
}
複製程式碼
總結
其實本文適用的範圍不僅僅侷限於前端,而是適用於所有使用了 git 作為版本控制的專案。例如安卓、ios、Java 等等。只是本文選擇了前端專案作為示例。
作者:譚光志
連結:https://juejin.cn/post/6986426226248253476
來源:稀土掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。