美文网首页
Git提交工作流提交信息校验

Git提交工作流提交信息校验

作者: 说叁两事 | 来源:发表于2024-05-23 18:34 被阅读0次

前置条件

环境版本

  • Node.js12+
  • npm 6+

熟知规范

每条提交信息都由页眉、正文和页脚组成。页眉有一种特殊格式,包括类型、范围和主题:

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

规范详见Angular提交规范

快速上手

安装依赖

npm install --save-dev husky
npx husky init
npm install --save-dev @commitlint/config-conventional @commitlint/cli

配置规范

在项目根目录下创建.commitlintrc.json

{
  "extends": [
    "@commitlint/config-conventional"
  ]
}

选择合适的git钩子

删除.husky/*内的其他hooks文件,更新.husky/commit-msg文件(若没有,则新建):

npx --no -- commitlint --edit $1
exit 1

测试

通过exit 1可以测试git commit命令,触发commit-msg钩子,而不会产生真实git提交。

定制化

@commitlint/cli从以下文件获取配置:

  • .commitlintrc
  • .commitlintrc.json
  • .commitlintrc.yaml
  • .commitlintrc.yml
  • .commitlintrc.js
  • .commitlintrc.cjs
  • .commitlintrc.mjs
  • .commitlintrc.ts
  • .commitlintrc.cts
  • commitlint.config.js
  • commitlint.config.cjs
  • commitlint.config.mjs
  • commitlint.config.ts
  • commitlint.config.cts

规则配置项由名称和配置规则组成。

配置规则可以是数组,也可以是返回数组的(异步)函数。

配置规则的数组包含:

  • Level[0..2]:
    • 0:忽略规则,不使用该条规则;
    • 1:触犯该规则视为警告,命令行有日志警告,命令照常执行;
    • 2:触犯该规则视为错误,命令行有日志报错,命令直接停止;
  • always|never
    • always:正向规则,该
    • never:逆向规则,
  • value:该规则使用的值。

规则解读:

  • 规则列表获取名称定义的具体规则;
  • 通过always|never判断规则的正逆;
  • 通过Level判断规则级别;
{
  "extends": [
    "@commitlint/config-conventional"
  ],
  "rules": {
     /**
     * 条件:type为空;
     * always|never: 逆向规则;
     * level:错误级别
     * 解读:type不能为空,违反该规则,报错,停止执行任务;
     */
    "type-empty": [2, "never"],
     /**
     * 条件:subject为空;
     * always|never: 正向规则;
     * level:错误级别
     * 解读:subject为空,违反该规则,报错,停止执行任务;
     */
    "subject-empty": [2, "always"],
     /**
     * 条件:type类型的值最长为72个字符;
     * always|never: 正向规则;
     * level:忽略规则
     * 解读:type类型的值最长为72个字符,违反该规则,没反应,相当于该规则无效;
     */
    'type-max-length': [0, 'always', 72],
    'header-max-length': async () => [0, 'always', 72], 
  }
}

规则配置示例见:https://commitlint.js.org/reference/rules-configuration.html

规则列表见:https://commitlint.js.org/reference/rules.html

CLI交互

通过上述配置,会在git commit提交stash的时候,校验提供的message信息是否符合规范。
该部分增加cli交互,提交git commit命令时,命令行会给出提示,可通过交互提交符合规范的message信息。

  1. 安装依赖

    npm install --save-dev commitizen
    npx commitizen init cz-conventional-changelog --save-dev --save-exact
    

    以上命令会自动执行以下任务:

    1. 安装cz-conventional-changelog适配器;

    2. package.json中添加config.commitizen配置,指定适配器:

      "config": {
          "commitizen": {
              "path": "./node_modules/cz-conventional-changelog"
          }
      }
      

      (可选项)手动将迁移到单独文件.czrc中:

      {
        "path": "./node_modules/cz-conventional-changelog"
      }
      
  2. 通过npx cz可以触发git commit的提示

  3. 将npx cz整合到git工作流中,让项目维护者不必不熟悉Commitizen的使用

    # 创建.husky/prepare-commit-msg
    exec < /dev/tty && node_modules/.bin/cz --hook || true
    

    即可通过git commit触发git commit提示。

  4. 优化prepare-commit-msg

    目前git commit -m "feat: 新功能"也会触发cz提示,这里做一下优化,符合规范的不做cz提示:

    commit_msg=`cat $1`
    msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
    if [[ $commit_msg =~ $msg_re ]] then
      exit 0
    else
      echo "\n不合法的 commit 消息提交格式,请使用正确的格式\n"
      exec < /dev/tty && node_modules/.bin/cz --hook || true
    fi
    

比较

规范 Git 提交信息的工具有:commitlintcommitizen

两者各有专攻,commitlint 校验提交信息,commitizen 辅助填写提交信息;

Git 提交工作流程中,commitlint 作用于 commit-msg 阶段,commitizen作用于 prepare-commit-msg

commitlint和配置文件.commitlintrc.json直接交流,将配置文件解析成后续能使用的规则集;

commitizen本身与提交信息规则并无关系。commitizen只提供与 Git 交互的框架,它传递 inquirer 对象给适配器(Adapter),由适配器负责描述命令行填写流程并返回用户填写的信息。借助cz-customizable配置文件.cz-config.js可实现自定义适配器。

整体定制化交互方案

了解 commitlintcommitizen 的机制之后,我们来考虑核心问题:怎么使两者共用同一份规则配置。

有两种思路:

  1. commitlint 配置出发,读取 commitlint 配置并生成对应的命令行提交流程,即创造一个 commitizen 适配器,@commitlint/cz-commitlint 已实现。
  2. cz-customizable 配置出发,将 cz-customizable 配置翻译为 commitlint 规则,即创造一个 commitlint 配置,commitlint-config-cz 已实现。

基于@commitlint/cli的解决方案适用于对已有规范(e.g. @commitlint/config-conventional)进行调整/扩展。

基于commitizen的解决方案适用于完全定制化。

基于@commitlint/cli

  1. 安装依赖

    npm install --save-dev husky @commitlint/cli @commitlint/config-conventional @commitlint/cz-commitlint commitizen
    npx husky init
    
  2. 自定义commitlint规范

    创建commitlint.config.js:

    export default { 
      extends: [
        '@commitlint/config-conventional'
      ],
      rules: {
        'type-enum': [2, 'always', ['foo']],
      },
    }
    
  3. 配置commitizen适配器

    创建.czrc文件,支持cz自定义适配器(Adapter),内容如下:

    {
      "path": "@commitlint/cz-commitlint"
    }
    
  4. 配置husky hooks

    1. 创建.husky/prepare-commit-msg,支持commitizen 适配器

      echo $0 # 打印当前执行的husky hook名称
      echo $1 # 打印当前执行的git hook名称
      echo `cat $1` # 打印当前执行的git hook参数值
      commit_msg=`cat $1`
      msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
      if [[ $commit_msg =~ $msg_re ]] then
        exit 0
      else
        echo "\n不合法的 commit 消息提交格式,请使用正确的格式\n"
        exec < /dev/tty && node_modules/.bin/cz --hook || true
      fi
      
    2. 创建.husky/commit-msg,支持commitlint

      npx --no -- commitlint --edit $1
      

基于commitizen

  1. 安装依赖

    npm install --save-dev husky commitizen cz-customizable commitlint-config-cz @commitlint/cli
    npx husky init
    
  2. 自定义commitizen配置

    1. 创建.czrc文件,支持commitizen自定义适配器(Adapter),内容如下:
      {
        "path": "./node_modules/cz-customizable"
      }
      
    2. 创建.cz-config.js,自定义适配器(Adapter):
      const path = require('path');
      const fs = require('fs');
      const appRootDir = 'apps'
      const projectJSONFile = 'project.json';
      const workspace = __dirname
      const appRootAbsoluteDir = path.resolve(workspace, appRootDir);
      const scopes = []
      try {
        const apps = fs.readdirSync(appRootAbsoluteDir)
        apps.forEach((appName) => {
          const filePath = path.resolve(appRootAbsoluteDir, appName, projectJSONFile)
          const file = fs.readFileSync(filePath, 'utf-8')
          const projectJson = JSON.parse(file)
          scopes.push(projectJson.name)
        })
      } catch {
      
      }
      const czConfig = {
        types: [
          {
            value: 'feat',
            name: 'feat:     A new feature'
          },
          {
            value: 'fix',
            name: 'fix:      A bug fix'
          },
          {
            value: 'docs',
            name: 'docs:     Documentation only changes'
          },
          {
            value: 'style',
            name: 'style:    Changes that do not affect the meaning of the code\n            (white-space, formatting, missing semi-colons, etc)',
          },
          {
            value: 'refactor',
            name: 'refactor: A code change that neither fixes a bug nor adds a feature',
          },
          {
            value: 'perf',
            name: 'perf:     A code change that improves performance',
          },
          {
            value: 'test',
            name: 'test:     Adding missing tests'
          },
          {
            value: 'chore',
            name: 'chore:    Changes to the build process or auxiliary tools\n            and libraries such as documentation generation',
          },
          {
            value: 'revert',
            name: 'revert:   Revert to a commit'
          },
          {
            value: 'WIP',
            name: 'WIP:      Work in progress'
          },
        ],
        scopes: [
          {
            value: '',
            name: 'empty'
          },
          ...scopes.map((name) => ({
            name
          }))
        ],
        usePreparedCommit: false, // to re-use commit from ./.git/COMMIT_EDITMSG
        allowTicketNumber: false,
        isTicketNumberRequired: false,
        ticketNumberPrefix: 'TICKET-',
        ticketNumberRegExp: '\\d{1,5}',
        messages: {
          type: "Select the type of change that you're committing:",
          scope: '\nDenote the SCOPE of this change:',
          subject: 'Write a SHORT, IMPERATIVE tense description of the change:\n',
          body: 'Provide a LONGER description of the change (optional). Use "|" to break new line:\n',
          breaking: 'List any BREAKING CHANGES (optional):\n',
          footer: 'List any ISSUES CLOSED by this change (optional). E.g.: #31, #34:\n',
          confirmCommit: 'Are you sure you want to proceed with the commit above?',
        },
      
        allowCustomScopes: false,
        allowBreakingChanges: ['feat', 'fix'],
        skipQuestions: ['body'],
        subjectLimit: 100
      };
      module.exports = czConfig;
      
    3. 创建.commitlintrc.json补充commitlint规范

    若仅以.cz-config.js定义的适配器执行husky hooks,会发现commitlint不起作用:

    commitlint-config-cz生成的commitlint 配置仅添加了上述的 type-enumscope-enum 规则(这些规则从您的 cz-customizable config 中读取)。
    这意味着 commitlnt 默认允许以空类型、空主题提交,因此还需要在.commitlintrc.json中添加类型为空、主题为空的规则。

    {
      "extends": [
        "cz"
      ],
      "rules": {
        "type-empty": [2, "never"],
        "subject-empty": [2, "never"]
      }
    }
    
  3. 配置husky hooks

    1. 创建.husky/prepare-commit-msg,支持commitizen自定义适配器(Adapter)
      echo $0 // 打印当前执行的husky hook名称
      echo $1 // 打印当前执行的git hook名称
      echo `cat $1` // 打印当前执行的git hook参数值
      commit_msg=`cat $1`
      msg_re="^(feat|fix|docs|style|refactor|perf|test|workflow|build|ci|chore|release|workflow)(\(.+\))?: .{1,100}"
      if [[ $commit_msg =~ $msg_re ]] then
        exit 0
      else
        echo "\n不合法的 commit 消息提交格式,请使用正确的格式\n"
        exec < /dev/tty && node_modules/.bin/cz --hook || true
      fi
      
    2. 创建.husky/commit-msg,支持commitlint
      npx --no -- commitlint --edit $1
      

特殊操作

忽略lint

git commit --amend

参考文档

相关文章

  • git提交规范

    Git 提交规范 制定一个 git commit 信息的提交规范是开发团队工作流必不可少的环节。试想一下,如果查看...

  • git常用命令

    git add . git commit -m "message"提交,其中message是提交的信息。 git ...

  • git命令第二章

    git commit -m "提交信息一" -m "提交信息二" 这里的-m参数,可以提交任意思多次的提交留...

  • git 修改最近的 commit message

    git 修改已经的提交信息 当我们使用 git 提交代码之后我们发现,提交信息描述有问题,想要仅仅修改描述信息而不...

  • DevOps之git日志信息解读

    DevOps之git日志信息解读 1 版本信息 2 提交作者 3 提交时间 4 提交mes...

  • git 常用的命令

    修改提交得message 拿出某次提交内容 合并提交的merge信息 查看提交记录 撤销commit git di...

  • git随笔

    git 常用操作 修改提交信息本地撤销修改记录git commit --amend通过此命令进入到提交信息界面,...

  • 撤回提交到 gitlab 上的代码

    step1 git log 查看分支上已提交的信息 会有每个提交信息的 commitId step2 git re...

  • git清空所有记录

    git 清空所有commit记录方法 说明:例如将代码提交到git仓库,将一些敏感信息提交,所以需要删除提交记录以...

  • 使用 husky + commitlint 检查提交描述是否符合

    使用 git hooks 来去校验我们的提交信息。 要完成这么个目标,那么我们需要使用两个工具: commitli...

网友评论

      本文标题:Git提交工作流提交信息校验

      本文链接:https://www.haomeiwen.com/subject/buwtqjtx.html