Git程式碼提交規範

當時明月在曾照彩雲歸發表於2023-04-26

1. 引言

思想,因人而異,難以重複

寫程式碼時,每個人的習慣是不一樣的,所以,引入了程式碼規範,為了省力,引入了自動格式化程式碼工具,前端工程中比較典型的自動格式化程式碼工具如:Prettier · Opinionated Code Formatter

日常多人協作寫程式碼時,需要不斷提交、推送、拉取程式碼,提交程式碼時,需要輸入一段Message來表述這次提交變更,思想因人而異,每個人寫的Message都風格各異,所以,引入了提交規範,以及引入了提交規範輔助工具

可以檢視一些經典開源專案的提交歷史:

image-20230425194817336

這些提交資訊看起來比較易讀且工整,表達資訊較為明確,整體較為規範

Git是常用的版本控制工具,本文描述使用Husky、commitlint等工具實現Git程式碼提交規範

2. Git Hooks

如同其他許多的版本控制系統一樣,Git 也具有在特定事件發生之前或之後執行特定指令碼程式碼功能(從概念上類比,就與監聽事件、觸發器之類的東西類似),Git Hooks 就是那些在Git執行特定事件(如commit、push、receive等)後觸發執行的指令碼,掛鉤是可以放置在掛鉤目錄中的程式,可在git執行的某些點觸發動作

使用Git Hooks可以實現:

  • 多人開發程式碼語法、規範強制統一
  • commit message 格式化、是否符合某種規範
  • 測試用例的檢測
  • 程式碼提交後的專案自動打包(git receive之後) 等

更為詳細的Git Hooks介紹與使用可以參考:

3. Husky

使用Git Hooks可以實現程式碼格式化、提交資訊規範化,但是需要手動編寫指令碼,而Husky就是簡化編寫這些指令碼的工具

Husky的官網:Husky - Git hooks (typicode.github.io)

參考官網,可以快速使用Husky:

安裝以及初始化

npx husky-init && npm install  

在專案中使用時,如果沒有package.json檔案會執行失敗,需先執行npm init

執行完上述命令後,可以發現專案中出現了新的資料夾.husky,下面有一個pre-commit

#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npm test

其作用主要是在commit之前執行npm test

為什麼會執行這個命令呢?因為在<專案名>/.git/config 中新配置有:

hooksPath = .husky

即,Git Hooks的目錄變更為.husky,Git處理時會自動應用該目錄中的指定的命令(如,提交前執行npm test

接下來,只需要安裝程式碼格式化工具並在pre-commit中寫入執行命令即可提交前自動格式化

4. ESLint

ESLint時常用的程式碼格式化工具,常用的還有Prettier

官網為:Find and fix problems in your JavaScript code - ESLint - Pluggable JavaScript Linter

參考官網的手冊:Getting Started with ESLint - ESLint - Pluggable JavaScript Linter

可以快速的使用ESLint:

安裝:

npm init @eslint/config

然後根據提示進行操作即可安裝完成

格式化檔案程式碼:

npx eslint yourfile.js

執行npx eslint <yourfile.js>即可格式化程式碼檔案

此處,當然可以提交前格式化所以程式碼檔案,但是,每次提交的檔案修改只是部分,並不需要把所有的程式碼檔案進行格式化操作

只需把提交修改的檔案,即暫存區的檔案進行格式化操作即可

5. lint-staged

見字識義,lint-staged工具就是對暫存區的程式碼檔案進行格式化

GitHub站點為:okonet/lint-staged: ?? — Run linters on git staged files (github.com)

根據站點的操作指南:okonet/lint-staged: ?? — Run linters on git staged files (github.com)

可以快速的使用lint-staged

安裝:

npm install --save-dev lint-staged

配置引數:

配置引數可以參考示例:okonet/lint-staged: ?? — Run linters on git staged files (github.com)

即,在 package.json 中新增"lint-staged": {},最後 package.json 形如

{
  "name": "My project",
  "version": "0.1.0",
  "scripts": {
    "my-custom-script": "linter --arg1 --arg2"
  },
  "lint-staged": {
      "*.{js,jsx}": "eslint"
  }
}

然後,在pre-commit中寫入執行命令即可提交前自動格式化程式碼:

npx lint-staged

接下來提交規範化

6. commitlint

commitlint是一個檢查提交是否符合規範的工具

官網為:commitlint - Lint commit messages

參考官網,可以快速的使用commitlint

安裝:

npm install @commitlint/cli @commitlint/config-conventional

配置:

echo "module.exports = {extends: ['@commitlint/config-conventional']}" > commitlint.config.js

注意:

  • 如果commitlint.config.js檔案不是utf8編碼,請儲存為utf8編碼
  • 此命令不應使用CMD來執行

執行命令寫入husky:

npx husky add .husky/commit-msg "npx --no -- commitlint --edit $1"

此時commitlint 具有預設的提交規範,參考:commitlint/@commitlint/config-conventional at master · conventional-changelog/commitlint (github.com)

7. Commitizen & cz-git

commitizen是基於Node.js的 git commit 命令列工具,輔助生成標準化規範化的 commit message,GitHub站點為:commitizen/cz-cli: The commitizen command line utility. #BlackLivesMatter (github.com)

cz-git:是一款工程性更強,輕量級,高度自定義,標準輸出格式的 commitizen 介面卡,官網為:快速開始 | cz-git (qbb.sh)

參考上述兩個官方文件,可以快速的使用這兩個工具:

安裝:

npm install -D commitizen cz-git

配置:

修改 package.json 指定使用的介面卡並新增 commit 指令:

{
  "scripts": {
	"commit": "git-cz"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-git"
    }
  }
}

此時,由於具有預設配置,在執行git add的情況下,直接執行npm run commit,就可以根據提示一步步的完善 commit msg 資訊:

npm run commit

> git-hooks@1.0.0 commit
> git-cz

cz-cli@4.3.0, cz-git@1.6.1

? Select the type of change that you're committing: Use arrow keys or
type to search
> feat:     A new feature
  fix:      A bug fix
  docs:     Documentation only changes
  style:    Changes that do not affect the meaning of the code
  refactor: A code change that neither fixes a bug nor adds a feature
  perf:     A code change that improves performance
  test:     Adding missing tests or correcting existing tests
(Move up and down to reveal more choices)

當然,可以根據:配置模板 | cz-git (qbb.sh),進行進一步的配置

筆者從下面文件中複製了一份配置:

commitlint.config.js檔案:

module.exports = {
  extends: ['@commitlint/config-conventional'],
  prompt: {
    messages: {
      type: '選擇你要提交的型別 :',
      scope: '選擇一個提交範圍(可選):',
      customScope: '請輸入自定義的提交範圍 :',
      subject: '填寫簡短精煉的變更描述 :\n',
      body: '填寫更加詳細的變更描述(可選)。使用 "|" 換行 :\n',
      breaking: '列舉非相容性重大的變更(可選)。使用 "|" 換行 :\n',
      footerPrefixesSelect: '選擇關聯issue字首(可選):',
      customFooterPrefix: '輸入自定義issue字首 :',
      footer: '列舉關聯issue (可選) 例如: #31, #I3244 :\n',
      generatingByAI: '正在透過 AI 生成你的提交簡短描述...',
      generatedSelectByAI: '選擇一個 AI 生成的簡短描述:',
      confirmCommit: '是否提交或修改commit ?'
    },
    // prettier-ignore
    types: [
      { value: 'feat', name: '特性:     ✨  新增功能', emoji: ':sparkles:' },
      { value: 'fix', name: '修復:     ?  修復缺陷', emoji: ':bug:' },
      { value: 'docs', name: '文件:     ?  文件變更', emoji: ':memo:' },
      { value: 'style', name: '格式:     ?  程式碼格式(不影響功能,例如空格、分號等格式修正)', emoji: ':lipstick:' },
      { value: 'refactor', name: '重構:     ♻️  程式碼重構(不包括 bug 修復、功能新增)', emoji: ':recycle:' },
      { value: 'perf', name: '效能:     ⚡️  效能最佳化', emoji: ':zap:' },
      { value: 'test', name: '測試:     ✅  新增疏漏測試或已有測試改動', emoji: ':white_check_mark:' },
      { value: 'build', name: '構建:     ?️  構建流程、外部依賴變更(如升級 npm 包、修改 vite 配置等)', emoji: ':package:' },
      { value: 'ci', name: '整合:     ?  修改 CI 配置、指令碼', emoji: ':ferris_wheel:' },
      { value: 'revert', name: '回退:     ⏪️  回滾 commit', emoji: ':rewind:' },
      { value: 'chore', name: '其他:     ?  對構建過程或輔助工具和庫的更改(不影響原始檔、測試用例)', emoji: ':hammer:' }
    ],
    useEmoji: true,
    emojiAlign: 'center',
    useAI: false,
    aiNumber: 1,
    themeColorCode: '',
    scopes: [],
    allowCustomScopes: true,
    allowEmptyScopes: true,
    customScopesAlign: 'bottom',
    customScopesAlias: 'custom',
    emptyScopesAlias: 'empty',
    upperCaseSubject: false,
    markBreakingChangeMode: false,
    allowBreakingChanges: ['feat', 'fix'],
    breaklineNumber: 100,
    breaklineChar: '|',
    skipQuestions: [],
    issuePrefixes: [{ value: 'closed', name: 'closed:   ISSUES has been processed' }],
    customIssuePrefixAlign: 'top',
    emptyIssuePrefixAlias: 'skip',
    customIssuePrefixAlias: 'custom',
    allowCustomIssuePrefix: true,
    allowEmptyIssuePrefix: true,
    confirmColorize: true,
    maxHeaderLength: Infinity,
    maxSubjectLength: Infinity,
    minSubjectLength: 0,
    scopeOverrides: undefined,
    defaultBody: '',
    defaultIssues: '',
    defaultScope: '',
    defaultSubject: ''
  }
}

此時在執行git add的情況下,執行npm run commit

PS E:\Code\test\Git-hooks> npm run commit

> git-hooks@1.0.0 commit
> git-cz

cz-cli@4.3.0, cz-git@1.6.1

? 選擇你要提交的型別 : Use arrow keys or type to search
❯ 特性:     ✨  新增功能
  修復:     ?  修復缺陷
  文件:     ?  文件變更
  格式:     ?  程式碼格式(不影響功能,例如空格、分號等格式修正)
  重構:     ♻️  程式碼重構(不包括 bug 修復、功能新增)
  效能:     ⚡️  效能最佳化
  測試:     ✅  新增疏漏測試或已有測試改動
(Move up and down to reveal more choices)

根據提示執行即可提交commit

8. 參考資料

[1] Git - githooks Documentation (git-scm.com)

[2] GitHook 工具 —— husky介紹及使用 - 較瘦 - 部落格園 (cnblogs.com)

[3] Husky - Git hooks (typicode.github.io)

[4] Find and fix problems in your JavaScript code - ESLint - Pluggable JavaScript Linter

[5] okonet/lint-staged: ?? — Run linters on git staged files (github.com)

[6] conventional-changelog/commitlint: ? Lint commit messages (github.com)

[7] commitlint - Lint commit messages

[8] commitizen/cz-cli: The commitizen command line utility. #BlackLivesMatter (github.com)

[9] cz-git | 一款工程性更強,輕量級,高度自定義,標準輸出格式的 Commitizen 介面卡 (qbb.sh)

[10] 【vue3-element-admin】Husky + Lint-staged + Commitlint + Commitizen + cz-git 配置 Git 提交規範 - 有來技術團隊 - 部落格園 (cnblogs.com)

相關文章