Git 提交信息规范

3,856 阅读5分钟

提交信息(Commit message),就是在项目的版本管理中,每次提交(commit)时要编写的那段提交信息。提交信息的主要用途是,告诉这个项目的其他人这次修改做了些什么。

  • 一般小步提交,防止一次提交修改过多的文件,导致后期的修改,维护和撤销困难;
  • 提交信息应该清晰明了,说明本次提交的目的。

为了标准化提交信息,便出现了一些写法规范。其中,使用较为广泛的是 AngularJS 的规范

格式

包括三个部分:Header,Body 和 Footer

<type>(<scope>): <subject>
<空行>
<body>
<空行>
<footer>

Header

包括三个字段:type(必需)、scope(可选)和subject(必需)

type

用于说明 commit 的类别,只允许使用下面7个标识:

  • feat:新功能(feature)
  • fix:修补bug
  • docs:文档(documentation)
  • style: 格式(不影响代码运行的变动)
  • refactor:重构(即不是新增功能,也不是修改bug的代码变动)
  • test:增加测试
  • chore:构建过程或辅助工具的变动

scope

用于说明 commit 影响的范围,可选值。通常是文件、路径、功能等。 Angular 项目中,scope 也指定了范围。

Subject

commit 目的的简短描述。不超过50个字符。

Body

commit 的详细描述。

Footer

  • Break Changes: 不兼容变动;BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
  • Closes: 关闭 Issue;如果当前 commit 针对某个issue,那么可以在 Footer 部分关闭这个 issue;如: Closes #123, #245, #992

Revert

特殊情况,在当前 commit 是用来撤销以前某个 commit 的时候。须以 revert: 开头,后面跟着被撤销 commit 的 Header。

另外

规范的 Commit message 除了手写外,也可以借助一些工具,帮助我们生成规范的提交信息。比如,Commitizen。

Commitizen

本着简单易操作的原则,我们参照 Commitizen 的手册来搞。

安装: 可以全局安装也可以本地安装,我更倾向用本地安装:

npm install --save-dev commitizen

本地安装,要使用 npx 命令初始化:

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

这行代码干了:

  1. 安装 cz-conventional-changelog;
  2. 更新 package.json 里的依赖项;
  3. package.json 里添加 config.commitizen 项:
"config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
}

全局安装的话,当需要 git commit 命令时,就可以使用 git cz了。 对于局部安装,每次使用 npx 不够优雅,一般会定义一个 npm 运行脚本,官方的例子:

"scripts": {
    "commit": "git-cz"
}

这时候,运行 npm run commit,会有如下提示:

git-cz

然后,按着提示一步一步搞就行了。

Vue

因为最近在看 Vue 的源码,下意识的去瞅了瞅 Vue 的 package.json:

  • 有 cz-conventional-changelog 依赖项;
  • 添加了 config.commitizen 项;
  • 有 commit 运行脚本。

所以,Vue 也是采用了上面的方式搞的。

changelog

规范提交信息还有一个目的,就是能够自动生成 changelog 文件。 Angular 使用了 git-release-notes 生成 changelog.md 的。

而 Vue 项目中没有 changelog.md 文件,其 changelog 在 release note 中。 Vue 也会生成 changelog 文件,只是没提交,作者把内容复制到了 release note 了。

Vue 中的 release:note 命令:

"release:note": "node scripts/gen-release-note.js",

gen-release-note.js 很简单,利用库 conventional-changelog 生成 changelog 文件:

const version = process.argv[2] || process.env.VERSION
const cc = require('conventional-changelog')
const file = `./RELEASE_NOTE${version ? `_${version}` : ``}.md`
const fileStream = require('fs').createWriteStream(file)

cc({
  preset: 'angular',
  pkg: {
    transform (pkg) {
      pkg.version = `v${version}`
      return pkg
    }
  }
})
  .pipe(fileStream)
  .on('close', () => {
    console.log(`Generated release note at ${file}`)
  })

在我们自己的项目中,可以像 Vue 一样写个脚本进行配置,但是,对于没有什么幺蛾子的小项目,用 conventional-changelog 提供的 CLI 版 更适合一些:

npm i -D conventional-changelog-cli

然后执行以下命令,可以生成 changelog 文件:

 npx conventional-changelog -p angular -i CHANGELOG.md -s

命令太长记不住,搞个 npm 运行脚本:

"scripts": {
    "release:note": "conventional-changelog -p angular -i CHANGELOG.md -s && git add CHANGELOG.md"
}

关于 conventional-changelog-cli 的其他玩法和工作流,移步这里

如此,便生成了一个看似很正经的 changelog 文件。在 GitLab 中预览一下:

changelog

检查提交信息

我们不能保证项目中每个人都严格遵守规则,所以同其他的规则的落地一样,需要通过检查工具来强制执行。 基本原理是在 git 的 commit-msg 钩子中去判断提交的信息是否合法。

除了自己在 .git/hooks 目录下手写 shell 脚本这种原始的方法外,市面上还有多种解决方案,大概看了一下后,我觉得去看看大牛是咋搞的。 依然是参考 Vue 项目:

原来(V2.5.14前)的 Vue 是这么干的:

  1. build/git-hooks/commit-msg 检查脚本内容如下:

    commit_regex='^Merge.+|(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert|types)(\(.+\))?: .{1,50}'
    
    if ! grep -iqE "$commit_regex" "$1"; then
        echo
        echo "  Error: proper commit message format is required for automated changelog generation."
        echo
        echo "  - Use \`npm run commit\` to interactively generate a commit message."
        echo "  - See .github/COMMIT_CONVENTION.md for more details."
        echo
        exit 1
    fi
    
  2. 克隆仓库后,需要运行 npm install & npm run setup,在 .git/hooks 下创建脚本的链接:

    "scripts": {
        "setup": "node build/setup.js"
    }
    

    setup.js:

    const { test, ln, chmod } = require('shelljs')
    
    function installHooks () {
        if (test('-e', '.git/hooks')) {
            ln('-sf', '../../build/git-hooks/commit-msg', '.git/hooks/commit-msg')
            chmod('+x', '.git/hooks/commit-msg')
        }
    }
    
    installHooks()
    

在 2.5.14之后的版本中,尤大用了自己的 yorkie,可以在 package.json 中很方便的定义git的各种钩子,并且也不需要 npm run setup 了。

"gitHooks": {
    "pre-commit": "lint-staged",
    "commit-msg": "node scripts/verify-commit-msg.js"
}

verify-commit-msg.js 的内容为:

const chalk = require('chalk')
const msgPath = process.env.GIT_PARAMS
const msg = require('fs').readFileSync(msgPath, 'utf-8').trim()

const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/

if (!commitRE.test(msg)) {
  console.log()
  console.error(
    `  ${chalk.bgRed.white(' ERROR ')} ${chalk.red(`invalid commit message format.`)}\n\n` +
    chalk.red(`  Proper commit message format is required for automated changelog generation. Examples:\n\n`) +
    `    ${chalk.green(`feat(compiler): add 'comments' option`)}\n` +
    `    ${chalk.green(`fix(v-model): handle events on blur (close #28)`)}\n\n` +
    chalk.red(`  See .github/COMMIT_CONVENTION.md for more details.\n`) +
    chalk.red(`  You can also use ${chalk.cyan(`npm run commit`)} to interactively generate a commit message.\n`)
  )
  process.exit(1)
}

实操

安装 yorkie 和 chalk

npm i -D yorkie chalk

package.json 中添加:

"gitHooks": {
    "commit-msg": "node build/verify-commit-msg.js"
}

在 build 目录下创建 verify-commit-msg.js 文件:

const chalk = require('chalk')
const msgPath = process.env.GIT_PARAMS
const msg = require('fs')
    .readFileSync(msgPath, 'utf-8')
    .trim()

const commitRE = /^(revert: )?(feat|fix|polish|docs|style|refactor|perf|test|workflow|ci|chore|types|build)(\(.+\))?: .{1,50}/

if (!commitRE.test(msg)) {
    console.log()
    console.error(
        `  ${chalk.bgRed.white(' 错误 ')} ${chalk.red(`提交信息的格式不正确。`)}\n\n` +
            chalk.red(`使用 npm run commit 或者使用格式正确的提交信息`)
    )
    process.exit(1)
}

更新

使用上面的方法,在 win10 系统中,无论在 powershell,cmd 还是 Windows Terminal 上,打印的文字只有白色(lint-staged 的打印也没有其他颜色),也没有 chalk 模块的啥报错。

另外:

  • yorkie 本身就 fork 自 husky;
  • yorkie 关闭了 Issue,社区支持差,使用者少。

于是,决定改用更通用的方案:husky

npm uninstall yorkie

npm i -D husky

package.json 将原来的 gitHooks 字段删掉,添加 husky 字段:

{
    "husky": {
        "hooks": {
            "commit-msg": "env FORCE_COLOR=1 node script/verify-commit-msg.js"
        }
    }
}

verify-commit-msg.js 更新:

// const msgPath = process.env.GIT_PARAMS  // 删掉这句

const msgPath = process.env.HUSKY_GIT_PARAMS;

参考