巧用 gitHooks 提交前校驗(yàn)代碼
感謝bigAken投稿
在每一個(gè)使用 git 進(jìn)行版本管理的倉庫,都有一個(gè)目錄 .git/hooks,包含 commit 各個(gè)階段 Hooks 的腳本。這些 Hooks 在 git 操作 commit、push、merge 等得時(shí)候,可以做前置或者后置的操作,例如 pre-commit 在 git commit 前可以做代碼校驗(yàn),校驗(yàn)代碼的時(shí)候使用的ESLint,格式化使用的是 prettier。Git 支持的常用鉤子見下表,更多請查看官網(wǎng)Hooks:
| Git Hook | 調(diào)用時(shí)機(jī) | 調(diào)用時(shí)機(jī) |
|---|---|---|
| pre-commit | git commit 執(zhí)行前 | 可以用 git commit --no-verify 繞過 |
| commit-msg | git commit 執(zhí)行前 | 可以用 git commit --no-verify 繞過 |
| pre-merge-commit | git merge 執(zhí)行前 | 可以用 git merge --no-verify 繞過 |
| pre-push | git push 執(zhí)行前 |
本文先實(shí)踐,怎么去寫 pre-commit 這個(gè) git hooks,然后介紹 husky,lint-staged,commitlint 的使用
在 git 項(xiàng)目中,.git/hooks下面有很多 hooks 示例如下
這些 git hooks 都是.sample結(jié)尾的,如果要啟用某個(gè) hooks 用可以去掉.sample結(jié)尾
實(shí)踐
npm init -y初始化一個(gè)項(xiàng)目,然后git init,然后npm install eslint --save-dev
新建.gitignore文件
node_modules
#?local?env?files
.env.local
.env.*.local
#?Log?files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*-lock.json
*.lock
新建.eslintrc,配置 eslint
{
?"rules":?{
??//?要求使用分號(hào)
??"semi":?["error",?"always"],
??//?強(qiáng)制使用一致的反勾號(hào)、雙引號(hào)或單引號(hào)
??"quotes":?["error",?"double"]
?}
}
新建src目錄,然后里面新建index.js,禁止使用快捷鍵格式化
console.log('object')
根目錄新建文件夾.customGitHooks然后 git config 'core.hooksPath' .customGitHooks,主要是設(shè)置 gitHooks 的存放目錄,因?yàn)?gitHooks 默認(rèn)存放目錄是.git/hooks,新建pre-commit,寫入如下
#!/bin/sh
echo?'start?check?your?code,please?wait...'
#?git?diff?獲取更改的內(nèi)容?可以通過參數(shù)--diff-filter?配置條件
npx?eslint?$(git?diff?--cached?--name-only?--diff-filter=ACM?--?'*.js')
#?變量$?--->上一個(gè)命令的執(zhí)行狀態(tài)結(jié)果
if?[?$??!=?'0'?];then
??echo?"ending and failed,please check your code;"
?exit?1
else
??echo?"check?pass"
fi
這時(shí)候,執(zhí)行git add .,git commit -m 'test'就會(huì)發(fā)現(xiàn)沒有 commit 成功,報(bào)錯(cuò)了,如下圖
如果把 index.js 的代碼修改如下:
console.log('object')
執(zhí)行git add . ,git commit -m 'test'就會(huì)發(fā)現(xiàn) eslint 代碼檢查通過了,能正常提交了,以上實(shí)踐能很好解釋 commit 前怎么檢驗(yàn)代碼,但是有個(gè)缺點(diǎn)就是別人 pull 你的代碼要執(zhí)行git config 'core.hooksPath' .customGitHooks能起作用;下面就介紹 husky,lint-staged,commitlint 的使用
.git 文件夾不會(huì)被跟蹤并且上傳至遠(yuǎn)程倉庫的
Husky
github為了解決.git配置不能提交遠(yuǎn)程倉庫的問題,husky 出來了,husky 在你npm i安裝完依賴只有自動(dòng)執(zhí)行husky install
安裝 npm install husky -D
npm?install?husky?-D
使用
編輯package.json在script里添加prepare的值為husky install
??"scripts":?{
????"prepare":"husky?install"
??},
然后執(zhí)行npm run prepare,做了什么事呢
源碼index.ts中,我們看到執(zhí)行 husky install 實(shí)際上就是創(chuàng)建 .husky 目錄,復(fù)制../husky.sh文件到該目錄下,配置了一個(gè).gitignore,設(shè)置了core.hooksPath(設(shè)置 .husky 目錄為 git hooks 目錄)
添加一個(gè) hook
在.husky目錄下創(chuàng)建pre-commit
#!/bin/sh
echo?'start?check?your?code,please?wait...'
#?git?diff?獲取更改的內(nèi)容?可以通過參數(shù)--diff-filter?配置條件
npx?eslint?$(git?diff?--cached?--name-only?--diff-filter=ACM?--?'*.js')
#?變量$?--->上一個(gè)命令的執(zhí)行狀態(tài)結(jié)果
if?[?$??!=?'0'?];then
??echo?"ending and failed,please check your code;"
?exit?1
else
??echo?"check?pass"
fi
index.js文件內(nèi)容如下
console.log('object')
然后執(zhí)行git add .,git commit -m 'test'發(fā)現(xiàn)代碼已經(jīng)被攔截,沒有提交,因?yàn)?code style="font-size: 14px;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">index.js代碼不符合規(guī)范
遺留問題就是 git hooks 不會(huì)編寫怎么辦,下面 lint-staged 出來了
lint-staged
配置例子作用:對 Git 暫存區(qū)代碼文件進(jìn)行 bash 命令操作等等
npm?i?lint-staged?-D
根目錄下新建.lintstagedrc文件
{
??"*.js":?"eslint"
}
把husky目錄下的pre-commit修改如下
.?"$(dirname?"$0")/_/husky.sh"
npm?run?lint
package.json添加script
"scripts":?{
??"lint":?"lint-staged"
}
index.js如下
console.log('object')
console.log('object')
執(zhí)行git add .,git commit -m 'test',可以發(fā)現(xiàn)調(diào)用了 eslint 去檢查代碼,檢查不通過就退出commit

綜上,代碼檢測規(guī)范有了,現(xiàn)在也需要規(guī)范一下提交規(guī)范;
commitlint
github
校驗(yàn) commit 提交的信息
npm install --save-dev @commitlint/config-conventional @commitlint/cli
使用新建commitlint.config.js
module.exports?=?{
?extends:?['@commitlint/config-conventional'],
?rules:?{
??'type-enum':?[2,?'always',?['build',?'ci',?'docs',?'feat',?'fix',?'perf',?'refactor',?'style',?'test',?'revert',?'chore']],
??'type-case':?[0],
??'type-empty':?[0],
??'scope-empty':?[0],
??'scope-case':?[0],
??'subject-full-stop':?[0,?'never'],
??'subject-case':?[0,?'never'],
??'header-max-length':?[0,?'always',?72]
?}
}
配置git hooks,執(zhí)行下面命令
npx?husky?add?.husky/commit-msg?'npx?--no?--?commitlint?--edit?$1'
commit message 一般分為三個(gè)部分 Header,Body 和 Footer
header
<type>():?
//?空一行
//?空一行
接下來提交的 commit 必須符合下面的格式
注意冒號(hào)后面有空格
git commit -m [optional scope]:
常用的 type 類別
build:主要目的是修改項(xiàng)目構(gòu)建系統(tǒng)(例如 glup,webpack,rollup 的配置等)的提交 ci:主要目的是修改項(xiàng)目繼續(xù)集成流程(例如 Travis,Jenkins,GitLab CI,Circle 等)的提交 docs:文檔更新 feat:新增功能 fix:bug 修復(fù) perf:性能優(yōu)化 refactor:重構(gòu)代碼(既沒有新增功能,也沒有修復(fù) bug) style:不影響程序邏輯的代碼修改(修改空白字符,補(bǔ)全缺失的分號(hào)等) test:新增測試用例或是更新現(xiàn)有測試 revert:回滾某個(gè)更早之前的提交 chore:不屬于以上類型的其他類型(日常事務(wù))
optional scope:一個(gè)可選的修改范圍。用于標(biāo)識(shí)此次提交主要涉及到代碼中哪個(gè)模塊。
description:一句話描述此次提交的主要內(nèi)容,做到言簡意賅。
這時(shí)候,執(zhí)行一次測試一下
git?add?.
git?commit?-m?'test'
因?yàn)樵撎峤坏?commit 是不規(guī)范的所以提交時(shí)失敗的 如下圖

如果把 commit 修改,就會(huì)提交成功,因?yàn)榉?commit 規(guī)范
git?add?.
git?commit?-m?'feat:?test'

但是問題又來了,每次 commit 都要輸入,有點(diǎn)不方便;而且有可能輸錯(cuò) 下面就介紹到 commitizen
commitizen
cz-commitlint
生成符合規(guī)范的 commit message
本地安裝并沒有全局安裝,當(dāng)然可以全局安裝具體查看官方文檔,全局安裝可以使用git cz,cz-commitlint打通 commitizen 和commitlint配置
npm?install?--save-dev?@commitlint/cz-commitlint?commitizen
然后
npx?commitizen?init?cz-conventional-changelog?--save-dev?--save-exact
package.json添加script
{
?"scripts":?{
??"commit":?"git-cz"
?},
?"config":?{
??"commitizen":?{
???"path":?"@commitlint/cz-commitlint"
??}
?}
}
新建commitlint.config.js
module.exports?=?{
?extends:?['@commitlint/config-conventional']
}
然后執(zhí)行
git?add?.
npm?run?commit
發(fā)現(xiàn)為中文提示如下圖
再次修改commitlint.config.js
module.exports?=?{
?extends:?['@commitlint/config-conventional'],
?prompt:?{
??questions:?{
???type:?{
????description:?'選擇你要提交的類型:',
????enum:?{
?????feat:?{
??????description:?'新功能',
??????title:?'Features',
??????emoji:?'?'
?????},
?????fix:?{
??????description:?'修復(fù)相關(guān)bug',
??????title:?'Bug?Fixes',
??????emoji:?'??'
?????},
?????docs:?{
??????description:?'文檔更改',
??????title:?'Documentation',
??????emoji:?'??'
?????}
????}
???}
??}
?}
}
然后執(zhí)行
git?add?.
npm?run?commit
可以看到變成中文了,具體參考官網(wǎng)
接下來提交信息 執(zhí)行npm run commit,就可以按照規(guī)范提交了;如果沒有使用commitlint,在 commitizen中使用 cz-customizable也可以自定義很多配置的
