Skip to content

提交规范-husky

初始化项目

bash
pnpm init

安装依赖

bash
pnpm add husky@8 -D
pnpm add @commitlint/cli -D
pnpm add @commitlint/config-conventional -D
pnpm add commitizen -D
pnpm add cz-git -D
  • @commitlint/cli

校验你写的 commit message 是否合规

  • @commitlint/config-conventional

提供一套「约定式提交」校验规则

  • commitizen

引导你“怎么写 commit”

  • cz-git

commitizen 的“现代增强版”,更灵活、好定制 中文汉化

  • husky

Husky 是一个用于在 Git 操作中自动运行脚本的工具。简单来说,它的主要作用是在 Git 的特定事件(如 commit 或 push)发生时,自动触发你预先定义好的命令。

在前端和后端开发中,Husky 最常见的用途是实现 Git Hooks(Git 钩子),以此来保证代码质量。

目录结构

bash

├── .husky
   └── commit-msg
├── .gitignore
├── commitlint.config.js
├── package.json
└── README.md

commitlint 安装

初始化

  • 初始化package.json
bash
pnpm init
  • 新建.gitignore
bash
node_modules

安装commitlint插件

bash
pnpm add -D @commitlint/cli @commitlint/config-conventional

commitlint.config.js

根目录创建commitlint.config.js文件,写入下面这段内容

js
import { defineConfig } from "cz-git";

export default defineConfig({
  // 继承 commitlint 的 conventional 规范
  // 约束最终生成的 commit message 格式
  extends: ["@commitlint/config-conventional"],

  // commitlint 校验规则(可按需补充)
  rules: {
    // @see https://commitlint.js.org/#/reference-rules
  },

  // cz-git 交互式提交配置
  prompt: {
    // 快捷别名:输入 fd 等价于 docs: fix typos
    alias: {
      fd: "docs: fix typos",
    },

    // 交互过程中的提示文案
    messages: {
      type: "选择你要提交的类型 :",
      scope: "选择一个提交范围(可选):",
      customScope: "请输入自定义的提交范围 :",
      subject: "填写简短精炼的变更描述 :\n",
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footerPrefixesSelect: "选择关联 issue 前缀(可选):",
      customFooterPrefix: "输入自定义 issue 前缀 :",
      footer: "列举关联 issue(可选)例如: #31, #I3244 :\n",
      confirmCommit: "是否提交或修改 commit ?",
    },

    // 提交类型(type)列表
    // 会作为第一步选择项
    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:    代码格式 | 不影响逻辑的样式调整" },
      { value: "refactor", name: "refactor: 代码重构 | 既不是修复也不是新增" },
      { value: "perf", name: "perf:     性能提升 | 提升性能的代码修改" },
      { value: "test", name: "test:     测试相关 | 测试用例新增或修复" },
      { value: "build", name: "build:    构建相关 | 构建系统或依赖变更" },
      { value: "ci", name: "ci:       持续集成 | CI 配置或脚本修改" },
      { value: "revert", name: "revert:   回退代码 | 回滚某次提交" },
      { value: "chore", name: "chore:    其他修改 | 非 src / test 变更" },
    ],

    // 是否在 commit message 中使用 emoji
    useEmoji: false,

    // emoji 对齐方式(启用 emoji 时生效)
    emojiAlign: "center",

    // 是否启用 AI 自动生成 commit 描述
    useAI: false,

    // AI 生成候选数量
    aiNumber: 1,

    // 主题色(用于终端高亮)
    themeColorCode: "",

    // 预定义的 scope 列表(为空表示不限制)
    scopes: [],

    // 是否允许自定义 scope
    allowCustomScopes: true,

    // 是否允许 scope 为空
    allowEmptyScopes: true,

    // 自定义 scope 选项在列表中的位置
    customScopesAlign: "bottom",

    // 自定义 scope 的别名
    customScopesAlias: "自定义",

    // 空 scope 的别名
    emptyScopesAlias: "空",

    // subject 是否强制首字母大写(null 表示不限制)
    upperCaseSubject: null,

    // 是否强制询问 breaking change
    markBreakingChangeMode: false,

    // 哪些 type 允许出现 breaking change
    allowBreakingChanges: ["feat", "fix"],

    // 每行最大长度(超出自动换行)
    breaklineNumber: 100,

    // 换行符号(body / breaking 中使用)
    breaklineChar: "|",

    // 跳过的提问步骤(例如 ['scope', 'body'])
    skipQuestions: [],

    // issue 前缀选项(常用于 gitee / gitlab)
    issuePrefixes: [
      // 关联 issue(进行中)
      { value: "link", name: "link:     链接 ISSUES 进行中" },
      // 关闭 issue
      { value: "closed", name: "closed:   标记 ISSUES 已完成" },
    ],

    // 自定义 issue 前缀位置
    customIssuePrefixAlign: "top",

    // 不关联 issue 的别名
    emptyIssuePrefixAlias: "空",

    // 自定义 issue 前缀别名
    customIssuePrefixAlias: "自定义",

    // 是否允许自定义 issue 前缀
    allowCustomIssuePrefix: true,

    // 是否允许不填写 issue
    allowEmptyIssuePrefix: true,

    // 提交确认阶段是否高亮显示
    confirmColorize: true,

    // 针对不同 type 覆盖 scope(未使用)
    scopeOverrides: undefined,

    // body 默认值
    defaultBody: "",

    // issue 默认值
    defaultIssues: "",

    // scope 默认值
    defaultScope: "",

    // subject 默认值
    defaultSubject: "",
  },
});

设置package.json

json
  "type": "module",

安装husky

bash
pnpm add -D husky@8

初始化Husky

bash
npx husky install
pnpm pkg set scripts.prepare="husky install"

配置 commit-msg 钩子函数

bash

npx husky add .husky/commit-msg 'npx --no -- commitlint --edit ${1}'

验证提交拦截

尝试提交一个不符合约定的提交的信息

bash
git add .
git commit -m "bad message"

你会看到类似以下报错,提交被阻止:

bash
   input: bad message
   subject may not be empty [subject-empty]
   type may not be empty [type-empty]

   found 2 problems, 0 warnings
   Get help: https://github.com/conventional-changelog/commitlint/#what-is-commitlint
  • 修改为符合规范的提交,例如:
bash
<type>(<scope>): <subject>

type:干啥
scope:哪儿
subject:怎么改
  • 提交测试
bash
git commit -m "feat: add error handling"
# 预期:提交成功

Commitizen 适配器

安装依赖

bash

pnpm add -D commitizen

pnpm add -D cz-git

配置 package.json

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

commitlint.config.js

js
import { defineConfig } from "cz-git";

export default defineConfig({
  // 继承 commitlint 的 conventional 规范
  // 约束最终生成的 commit message 格式
  extends: ["@commitlint/config-conventional"],

  // commitlint 校验规则(可按需补充)
  rules: {
    // @see https://commitlint.js.org/#/reference-rules
  },

  // cz-git 交互式提交配置
  prompt: {
    // 快捷别名:输入 fd 等价于 docs: fix typos
    alias: {
      fd: "docs: fix typos",
    },

    // 交互过程中的提示文案
    messages: {
      type: "选择你要提交的类型 :",
      scope: "选择一个提交范围(可选):",
      customScope: "请输入自定义的提交范围 :",
      subject: "填写简短精炼的变更描述 :\n",
      body: '填写更加详细的变更描述(可选)。使用 "|" 换行 :\n',
      breaking: '列举非兼容性重大的变更(可选)。使用 "|" 换行 :\n',
      footerPrefixesSelect: "选择关联 issue 前缀(可选):",
      customFooterPrefix: "输入自定义 issue 前缀 :",
      footer: "列举关联 issue(可选)例如: #31, #I3244 :\n",
      confirmCommit: "是否提交或修改 commit ?",
    },

    // 提交类型(type)列表
    // 会作为第一步选择项
    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:    代码格式 | 不影响逻辑的样式调整" },
      { value: "refactor", name: "refactor: 代码重构 | 既不是修复也不是新增" },
      { value: "perf", name: "perf:     性能提升 | 提升性能的代码修改" },
      { value: "test", name: "test:     测试相关 | 测试用例新增或修复" },
      { value: "build", name: "build:    构建相关 | 构建系统或依赖变更" },
      { value: "ci", name: "ci:       持续集成 | CI 配置或脚本修改" },
      { value: "revert", name: "revert:   回退代码 | 回滚某次提交" },
      { value: "chore", name: "chore:    其他修改 | 非 src / test 变更" },
    ],

    // 是否在 commit message 中使用 emoji
    useEmoji: false,

    // emoji 对齐方式(启用 emoji 时生效)
    emojiAlign: "center",

    // 是否启用 AI 自动生成 commit 描述
    useAI: false,

    // AI 生成候选数量
    aiNumber: 1,

    // 主题色(用于终端高亮)
    themeColorCode: "",

    // 预定义的 scope 列表(为空表示不限制)
    scopes: [],

    // 是否允许自定义 scope
    allowCustomScopes: true,

    // 是否允许 scope 为空
    allowEmptyScopes: true,

    // 自定义 scope 选项在列表中的位置
    customScopesAlign: "bottom",

    // 自定义 scope 的别名
    customScopesAlias: "自定义",

    // 空 scope 的别名
    emptyScopesAlias: "空",

    // subject 是否强制首字母大写(null 表示不限制)
    upperCaseSubject: null,

    // 是否强制询问 breaking change
    markBreakingChangeMode: false,

    // 哪些 type 允许出现 breaking change
    allowBreakingChanges: ["feat", "fix"],

    // 每行最大长度(超出自动换行)
    breaklineNumber: 100,

    // 换行符号(body / breaking 中使用)
    breaklineChar: "|",

    // 跳过的提问步骤(例如 ['scope', 'body'])
    skipQuestions: [],

    // issue 前缀选项(常用于 gitee / gitlab)
    issuePrefixes: [
      // 关联 issue(进行中)
      { value: "link", name: "link:     链接 ISSUES 进行中" },
      // 关闭 issue
      { value: "closed", name: "closed:   标记 ISSUES 已完成" },
    ],

    // 自定义 issue 前缀位置
    customIssuePrefixAlign: "top",

    // 不关联 issue 的别名
    emptyIssuePrefixAlias: "空",

    // 自定义 issue 前缀别名
    customIssuePrefixAlias: "自定义",

    // 是否允许自定义 issue 前缀
    allowCustomIssuePrefix: true,

    // 是否允许不填写 issue
    allowEmptyIssuePrefix: true,

    // 提交确认阶段是否高亮显示
    confirmColorize: true,

    // 针对不同 type 覆盖 scope(未使用)
    scopeOverrides: undefined,

    // body 默认值
    defaultBody: "",

    // issue 默认值
    defaultIssues: "",

    // scope 默认值
    defaultScope: "",

    // subject 默认值
    defaultSubject: "",
  },
});

package.json

json
{
  "name": "mycomponent",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepare": "husky install",
    "commit": "git-cz"
  },
  "config": {
    "commitizen": {
      "path": "node_modules/cz-git"
    }
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "packageManager": "pnpm@10.15.1",
  "devDependencies": {
    "@commitlint/cli": "^20.3.1",
    "@commitlint/config-conventional": "^20.3.1",
    "commitizen": "^4.3.1",
    "cz-git": "^1.12.0",
    "husky": "^8.0.3"
  },
  "type": "module"
}

使用

添加到暂存区

  • 这一步百度下vscode 怎么使用 git 即可

运行命令

bash

npm run commit

结果如图所示