由于近半年來接觸到的項(xiàng)目中Git Commit都沒有做限制,不規(guī)范的Git Commit提交使得現(xiàn)有項(xiàng)目的Git Log雜亂無章。長此以往,當(dāng)我們需要項(xiàng)目復(fù)盤、code review或者日常查詢以往功能的時候分不清哪些是新功能、哪些是修復(fù)bug等等。
例如,我們在2021年開發(fā)了一個功能,后來由于項(xiàng)目不再需要此功能從代碼中刪除了。在2022年的時候其他需求中也用到了這個功能,這時候如果我們沒有一個合理的git commit提交規(guī)范,以目前的git commit描述是很難找到這個功能的代碼的。尤其是在多人協(xié)作的團(tuán)隊(duì)項(xiàng)目中,這種弊端更為明顯。
因此規(guī)范團(tuán)隊(duì)的提交是非常有必要的,所以git commit規(guī)范約束就特別需要了。
以下為一個無commit message規(guī)范的git提交記錄,可以看到commit message沒有規(guī)范約束,可隨意錄入任何內(nèi)容,無論它與提交內(nèi)容是否一致。

所以我們今天要說的就是為commit message提供一個約束,使我們的提交信息更為規(guī)范,能夠一目了然的知道我們這次提交是什么內(nèi)容。
下面這張圖是經(jīng)過git commit規(guī)范約束后的commit message:

我們可以看到此條message的大致格式為:<type>(<scope>): <subject>,下面將會詳細(xì)介紹git commit規(guī)范的格式和檢測工具的具體配置方式。
Commit Message格式
要想規(guī)范git commit 提交,我們先要了解一下Commit Message格式,目前規(guī)范使用較多的是 Angular 團(tuán)隊(duì)的規(guī)范, 這是目前使用最廣的寫法,比較合理和系統(tǒng)化。繼而衍生了 Conventional Commits specification. 很多工具也是基于此規(guī)范, 它的 message 格式如下:
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer></footer>
Commit message 都包括三個部分:Header,Body 和 Footer,其中,Header 是必需的,Body 和 Footer 可以省略。不管是哪一個部分,任何一行都不得超過100個字符。這是為了避免自動換行影響美觀。
由于Body和Footer不是必需的,我們?nèi)粘S玫降囊脖容^少,這里不再多做闡述,我們重點(diǎn)介紹一下Header部分。
Header部分只有一行,包括三個字段:type(必需)、scope(可選)和subject(必需)。注意冒號后面有空格
- type(必填)
type用于說明 commit 的類別。
* feat:新增功能
* fix:bug 修復(fù)
* docs:文檔更新
* style:不影響程序邏輯的代碼修改(修改空白字符,格式縮進(jìn),補(bǔ)全缺失的分號等,沒有改變代碼邏輯)
* refactor:重構(gòu)代碼(既沒有新增功能,也沒有修復(fù) bug)
* perf:性能, 體驗(yàn)優(yōu)化
* test:新增測試用例或是更新現(xiàn)有測試
* build:主要目的是修改項(xiàng)目構(gòu)建系統(tǒng)(例如 glup,webpack,rollup 的配置等)的提交
* ci:主要目的是修改項(xiàng)目繼續(xù)集成流程(例如 Travis,Jenkins,GitLab CI,Circle等)的提交
* chore:不屬于以上類型的其他類型,比如構(gòu)建流程, 依賴管理
* revert:回滾某個更早之前的提交
scope(可選)
scope用于說明 commit 影響的范圍,比如數(shù)據(jù)層、控制層、視圖層等等,視項(xiàng)目不同而不同。subject(必填)
subject是 commit 目的的簡短描述。
- 以動詞開頭,使用第一人稱現(xiàn)在時,比如change,而不是changed或changes;
- 第一個字母小寫;
- 結(jié)尾不加句號(.)
使用commitlint工具來檢驗(yàn)commit格式是否符合規(guī)范
上面我們已經(jīng)了解了Commit Message的格式是什么樣的了,如果讓我們自己手動敲出那些格式也不是不可能,但是我們都知道人工輸入難免會有失誤的時候,我們借助commitlint工具進(jìn)行commit格式是否符合規(guī)范。
- 安裝commitlint cli
npm install --save-dev @commitlint/config-conventional @commitlint/cli
- 配置commitlint使用傳統(tǒng)的config配置文件
可以在項(xiàng)目根目錄使用命令行生成(如下所示),也可以直接在根目錄手動創(chuàng)建commitlint.config.js文件
echo module.exports = {extends: ['@commitlint/config-conventional']} > commitlint.config.js
自動生成的配置文件采用commitlint默認(rèn)的配置,如下所示:
module.exports = { extends: ['@commitlint/config-conventional'] };
當(dāng)然,你也可以配置rules,自定義規(guī)則:
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [
2,
'always',
['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'revert']
],
'subject-full-stop': [0, 'never'],
'subject-case': [0, 'never'],
'header-max-length': [0, 'always', 72]
}
};
rule配置說明:rule由name和配置數(shù)組組成,如:name:[0, 'always', 72]。
- 數(shù)組中第一位為level,可選0、1、2。0為禁用,1為警告,2為錯誤;
- 第二位為應(yīng)用與否,可選always|never;
- 第三位該rule的值。
Git Hooks
commitlint本身只是一個檢測工具,想要讓它真正發(fā)揮作用,需要與git hooks相結(jié)合。而husky 是一個 Git Hook 工具,一個為 git 客戶端增加 hook 的工具,husky繼承了Git下所有的鉤子,在觸發(fā)鉤子的時候,husky可以阻止不合法的commit,push等等。這里我分需要分成三個部分來講解:
Husky5.0版本以下,以4.3.8為例
- husky安裝
npm install husky --save-dev
- 把commitline配置到githook鉤子中,如果package.json文件中已經(jīng)配置了husky,直接追加上去即可,如果沒有配置,則添加以下代碼
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},
這段配置告訴了git hooks,當(dāng)我們在當(dāng)前項(xiàng)目中執(zhí)行 git commit -m '測試提交'時將觸發(fā)commit-msg事件鉤子并通知husky,從而執(zhí)行commitlint -E HUSKY_GIT_PARAMS命令,也就是我們剛開始安裝的 ./node_modules/.bin/ commitlint,它將讀取commitlint.config.js配置規(guī)則并對我們剛剛提交的“測試提交”這串文字進(jìn)行校驗(yàn),若校驗(yàn)不通過,則在終端輸出錯誤,commit終止。
使用commit-msg給出了我們想要的東西:只要創(chuàng)建新的提交就會執(zhí)行它。傳遞husky的 HUSKY_GIT_PARAMS 給 commitlint 通過 -E|--env 標(biāo)記它引導(dǎo)到相關(guān)的編輯文件。-E默認(rèn)為 .git/COMMIT_EDITMSG 。



從上面三張圖片中可以看到,當(dāng)手動提交git commit -m “aaa”和git commit -m “abc: aaaaa”時,由于不符合規(guī)則,就會報(bào)錯,不通過了。只有把必填的都寫上,符合規(guī)則才可以通過。
Husky5.0版本以上,以7.0.4為例
我們有時候會發(fā)現(xiàn),按照以上步驟配置完成后 git commit的時候還是沒有效果,沒有去執(zhí)行husky配置的鉤子。因?yàn)镠usky升級到5.0版本以上后,在配置上與4.x版本有所差別,按上面的配置只適用于4.x,這里簡要概況一下。
- 依然需要先安裝husky,由于現(xiàn)在husky版本已經(jīng)7.x了,如果不指定版本,默認(rèn)安裝的是最新版本,這里我們使用官方推薦的自動安裝的的方式,你也可以選擇使用傳統(tǒng)方式分步安裝,具體步驟在這里:husky傳統(tǒng)安裝步驟
npx husky-init && npm install
安裝后觀察package.json文件,如果版本高于5.0,那么就用這個單元里的方案
"husky": "^7.0.4",
并且項(xiàng)目根目錄下會多一個.husky文件夾,里面會有個pre-commit文件,這個文件就是在commit之前會執(zhí)行的一個Hook(這里可以打開pre-commit文件看一下,如果默認(rèn)里面是npm test,把他刪除掉,不然后面會報(bào)錯)

- 配置commit-msg鉤子
執(zhí)行以下命令,在生成的commit-msg文件中手動鍵入npx --no-install commitlint --edit "$1"(這里已經(jīng)試過,按照官方提供的方式直接執(zhí)行npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'命令無法生成commit-msg文件)
npx husky add .husky/commit-msg
完成以上兩個步驟以后,就可以去git commit測試一下是否已經(jīng)配置完成。當(dāng)然,我們也可以去pre-commit文件下配置一下代碼過濾工具。
vue-cli創(chuàng)建的項(xiàng)目中的gitHooks
在使用 vue create xxx 創(chuàng)建項(xiàng)目的時候,Vue 會自動幫我們做好一些預(yù)配置,其中就有一個叫做yorkie的包,這個包是尤大 fork 自husky?的,它倆功能是一樣的,都是生成一些 git hooks 文件,讀取項(xiàng)目中 package.json 的相關(guān)配置項(xiàng)去執(zhí)行一些命令,區(qū)別是尤大做了一些邏輯和配置上的改動。
yorkie的流程解析就不在這里細(xì)說,感興趣的可以自行去網(wǎng)上查詢資料,總之,在使用vue-cli創(chuàng)建的項(xiàng)目中可以不安裝husky,直接配置gitHooks,當(dāng)然你也可以使用husky的方式,這沒有任何問題,一切根據(jù)個人習(xí)慣而定。
下面講一下在vue項(xiàng)目中配置gitHooks的另一種方式:在vue-cli創(chuàng)建的環(huán)境中使用gitHooks是非常簡單的,只需要commitlint cli安裝安成后,在package.json文件中直接通過字段直接添加git鉤子即可。
"gitHooks": {
"commit-msg": "commitlint -E GIT_PARAMS"
},
這里我們拓展一下知識點(diǎn),我們知道commit-msg是一個git鉤子,當(dāng)然除了commit-msg,git還有很多的其他的鉤子,現(xiàn)在我們就來聽過pre-commit這個鉤子來配置一下代碼過濾工具,以防止不小心把錯誤的代碼提交到git上。
- 安裝lint-staged,這里用到的lint-staged版本為10.2.11,建議不要隨意改動版本
npm install lint-staged --save-dev
- 在package.json中定義gitHooks
"gitHooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E GIT_PARAMS"
},
- 配置前端文件過濾工具lint-staged,這里用了vue-cli-service,當(dāng)然你也可以選擇用eslint等代碼檢測工具。
"lint-staged": {
"*.{js,vue}": [
"vue-cli-service lint",
"git add"
]
},