8

规范化git commit信息 - DTeam 团队日志

 4 years ago
source link: https://blog.dteam.top/posts/2019-04/%E8%A7%84%E8%8C%83%E5%8C%96git-commit%E4%BF%A1%E6%81%AF.html?
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在 git 的使用中,一种最佳实践是使用格式化的 commit 信息,这样方便自动化工具进行处理,可以快速生成 Release Notes,甚至可以直接对接 CI 工具进行更进一步的规范化发布流程。那么如何规范化 git commit 信息呢?本文将重点讨论这个。

2020-05-21 更新:为了更加轻量化,使用git-cz替换掉原来主要推荐的commitlizen部分,在最后添加了一个小结部分概览,方便快速在本地开发环境速查命令及使用方式。

一个最基本的 git commit 最佳实践

Git-Commit-Best-Practices这个项目总结了一个最基本的 git commit 实践:

  • Commit Related Changes
  • Commit Often
  • Don’t Commit Half-Done Work
  • Test Your Code Before You Commit
  • Write Good Commit Messages
  • Use Branches
  • Agree on A Workflow

而针对其中的Formatting Rules部分,我们将详细讲解下 Angular 的 git commit 规范格式。

Angular 项目的 git commit 规范

首先我们先了解一下Angular项目如何规范化自己的 commit 信息的吧。

Angular 项目可以说是业界最广为流传的 git commit 最佳实践的项目。Angular 的贡献要求必须 git commit 符合自己定义的模板。先来看看 Angular 的 commit 记录长什么样子吧: https://github.com/angular/angular/commits/master

image.png

这样的话 Angular 项目组可以很方便的生成Release Notes

image.png

Angular 的 git commit 实践

完整的 Angular 的 commit 教程参见的 CONTRIBUTING: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines

Angular 定义的 commit 基本格式如下:

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

除了第一行的 Header 部分必填外,其余均可选。注意 Header, Body, Footer 中间有空白行分割。

image.png

Header 部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。

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

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

通常featfix会被放入 changelog 中,其他(docschorestylerefactortest)通常不会放入 changelog 中。

scope用于说明 commit 影响的范围,可选值。通常是文件、路径、功能等。对于 Angular 项目已经定死了 scope: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#scope

subject是 commit 目的的简短描述,不超过 50 个字符。如用英语表述:

  • 以动词开头,使用第一人称现在时,比如change,而不是changedchanges
  • 第一个字母小写
  • 结尾不加句号(.

Body部分是对本次 commit 的详细描述,可以分成多行。可选项。范例:

More detailed explanatory text, if necessary. Wrap it to
about 72 characters or so.

Further paragraphs come after blank lines.

- Bullet points are okay, too
- Use a hanging indent

Footer 部分只用于两种情况:

  • Break Changes
  • Closes

Break Changes 范例:

BREAKING CHANGE: isolate scope bindings definition has changed.

    To migrate the code follow the example below:

    Before:

    scope: {
      myAttr: 'attribute',
    }

    After:

    scope: {
      myAttr: '@',
    }

    The removed `inject` wasn't generaly useful for directives so there should be no code using it.

Closes 范例:

Closes #123, #245, #992

自动化工具处理 git commit

手写上述的 commit 格式很明显并不怎么方便,而且还有出错的可能性(尽管 git 支持template功能,但是实际使用的时候仍然不是特别方便),为什么不交给自动化工具完成呢?

下面就是重点要介绍的规范化 git commit 消息的工具git-cz

git-cz是一个简化版的commitizen+cz-conventional-changelog组合,提供了开箱即用的功能,默认使用Angular规范,默认模板不填写scope部分内容。

NOTE: Windows 环境下你需要使用cmdpowershell运行交互式终端,在cygwin/mingw32/msys2等模拟 posix 运行环境下无法正常执行交互式终端菜单。

NOTE: git-cz非常轻量,只提供 Angular 规范的支持。如果你想使用其他规范的 commit,请使用commitizen配合对应的Adapter

对于 NodeJS 项目,commitizen 可以将自己的一些脚本添加到package.json中,方便npm script生命周期管理。

快速将一个项目初始化为 commitizen 友好的项目(需要确保当前工程中必须存在package.json文件):

# 将git-cz命令行安装到全局
npm install -g git-cz

# 也可以使用npx命令直接运行
npx git-cz

此时git czgit-cz命令将出现类似于下面的交互式终端:

[email protected], [email protected]


Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.

? Select the type of change that you're committing: (Use arrow keys)
❯ feat:     A new feature
  fix:      A bug fix
  docs:     Documentation only changes
  style:    Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  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)
image

按照之前的 Angular commit 规范格式交互式输入信息即可,是不是比手写方便了许多?

以后,只要是需要git commit的地方,通通替换为git czgit-cz即可这样交互式的输入符合 Angular commit 规范的 git log 了。其余 commit 的参数也兼容,比如-a, --amend等等。

自动检测 commit 是否符合规范

尽管我们可以在 CI 测试阶段检测 commit 是否符合这个规范,但是能在本地就有反馈不是更快吗?因此我们可以考虑在git commithook中加入commitlint检测,不符合 commit 规范的提交在本地就无法提交进去。

对于 NodeJS 项目来说,有个非常简单的使用 git hook 的项目husky,使用者无需手工定义繁琐的 git hook 脚本,直接在package.json中定义要执行的 hook 命令即可。

在项目依赖中添加husky:

npm i -D husky

然后在package.json配置中添加husky的 git hook 配置:

{
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -x @commitlint/config-conventional -E HUSKY_GIT_PARAMS"
    }
  }
}

然后安装@commitlint/cli@commitlint/config-conventional这两个包(建议安装到全局,这样所有项目都可以用):

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

这样如果使用普通的 git commit 提交了不符合 commit 规范的消息,就会被直接打回:

 git commit -a -m '添加husky和commitlint依赖'
husky > commit-msg (node v10.15.3)

⧗   input: 添加husky和commitlint依赖
✖   subject may not be empty [subject-empty]
✖   type may not be empty [type-empty]
✖   found 2 problems, 0 warnings
    (Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )


husky > commit-msg hook failed (add --no-verify to bypass)

可以看到git commit触发了husky的 hook,告诉用户这条 commit 记录不符合 Angular 规范。

再次使用git cz提交一次:

 git cz -a
[email protected], [email protected]


Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.

? Select the type of change that you're committing: build:    Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
? What is the scope of this change (e.g. component or file name)? (press enter to skip)
 package.json
? Write a short, imperative tense description of the change:
 添加husky和commitlint提交前检测
? Provide a longer description of the change: (press enter to skip)

? Are there any breaking changes? No
? Does this change affect any open issues? No

husky > commit-msg (node v10.15.3)

⧗   input: build(package.json): 添加husky和commitlint提交前检测
✔   found 0 problems, 0 warnings
    (Need help? -> https://github.com/conventional-changelog/commitlint#what-is-commitlint )


[master bd79828] build(package.json): 添加husky和commitlint提交前检测
 2 files changed, 1357 insertions(+), 7 deletions(-)

符合 commit 规范的提交可以成功提交到版本库中。

NOTE: 巧妙合理利用 husky 的 hook 功能可以大大规范化开发。比如在pre-commit 这个 hook 中加入各种 lint(eslink, tslink, jslint 等)检测,大大提高代码规范化效率,减少 BUG 产生。

对于非 NodeJS 项目,可以将commitlint安装为全局的命令行工具独立使用。

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

每次 commit 之后可以使用下述命令检测:

commitlint -x '@commitlint/config-conventional' -e

-e/--edit参数代表读取 git commit 最后一条记录。如果希望检测最近几条 commit 记录,可以用:

commitlint -x '@commitlint/config-conventional' -f HEAD~1

-f/--from参数可以指明从哪一条 commit 记录开始检测,还可以配合-t/--to参数检测一个 commit 区间段。

NOTE: 如果不介意非 NodeJS 项目下多一堆 NodeJS 项目相关的配置文件,也可以在npm init初始化成 nodejs 项目之后走上述 NodeJS 项目的配置流程。

重头戏来了。规范化 commit 记录的作用就是为了方便我们知道每次发布之后到底改了什么内容。利用conventional-changelog这个工具可以很方便的帮我们产生 changelog。

npm install -g conventional-changelog-cli

如果之前每次 commit 都使用规范化的 commit 提交,那么使用:

conventional-changelog -p angular

应该看到这样的 markdown:

# (2019-04-25)

### Bug Fixes

- **third.md:** 添加新的 third.md 文件,添加一个新功能 719c542

### Features

- **new.md:** 添加新的功能项 43d6584
- **README.md:** 初始化项目工程 69c6c9f

### BREAKING CHANGES

- **new.md:** 这个功能打破了一个函数。before: old, new: new

这就是一个基本的CHANGELOG.md雏形,你可以自己复制到CHANGELOG.md并进行相应的修改。也可以直接输出到CHANGELOG.md文件中:

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

终端中看到的内容将输出到CHANGELOG.md文件。再次使用上述命令可以将新的 change log 追加到文件中。可以追加-r 0参数代表将 commit 记录从头至尾全部生成 changelog。

更自动化的发布方式 standard-version

conventional-changelog的官方文档中,官方更鼓励使用更上层的工具standard-version来产生CHANGELOG.mdconventional-changelog可以帮助我们快速检查要生成的 CHANGELOG.md 的格式是否符合期望,而standard-version可以自动帮助我们做以下几件事情:

  • 升级元数据中的版本号(如package.json,composer.json等等)
  • 使用conventional-changelog更新  CHANGELOG.md
  • 提交package.json (如果有) 和 CHANGELOG.md
  • 给新版本打一个 tag

首先安装 standard-version 到全局命令行:

npm i -g standard-version

执行下standard-version,将看到类似于下面这样的输出:

 standard-version
✔ created CHANGELOG.md
✔ outputting changes to CHANGELOG.md
✔ committing CHANGELOG.md
✔ tagging release v2.0.0
ℹ Run `git push --follow-tags origin master && npm publish` to publish

可以非常清楚的从终端上看到standard-version做了哪些事情。检查 git log 可以看到新增了一条 commit 记录:

commit cac4b5cda4f0c2a78928d8306c5c2eab8c590f02 (HEAD -> master, tag: v2.0.0)
Author: Your Name <[email protected]>
Date:   Thu Apr 25 17:15:56 2019 +0800

    chore(release): 2.0.0

项目中也生成了一个CHANGELOG.md文件:

# Change Log

All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.

# (2019-04-25)

### Bug Fixes

- **third.md:** 添加新的 third.md 文件,添加一个新功能 719c542

### Features

- **new.md:** 添加新的功能项 43d6584
- **other.md:** 新增一个 other.md 文件,记录了新的内容 1a204d9
- **README.md:** 初始化项目工程 69c6c9f

### BREAKING CHANGES

- **new.md:** 这个功能打破了一个函数。before: old, new: new

standard-version 一些基本用法

直接跟空参运行的行为我们已经看到了,一些基本参数介绍下:

  • --dry-run: 强烈建议正式运行之前先加这个参数,打印一下要做的事情,并不真正执行
  • --first-release/-f: 首次发布,加上这个参数代表不会升级版本号。仅第一次使用需要
  • --commit-all/-a: 等效于git commit -a,建议自己决定要提交哪些文件,都add没问题之后再执行standard-version
  • --release-as/-r: 手工指定下一个版本号(格式<major|minor|patch>)。这个参数可能会经常使用。standard-version默认规则是从major/minor/patch中最后一个非零的字段开始累加,如v1.0.0 -> v2.0.0, v1.1.0 -> v1.2.0, v1.1.1 -> v1.1.2,指定这个参数可以规避这个规则,从自定义的版本号开始重新按上述规则升级
  • --prerelease/-p: 预发布版本,默认产生的 tag 像这样: v1.0.1-0。可以跟上一个可选的 tag id。如-p alpha,将产生这样的 tag: v1.0.1-alpha.0

直接结合semantic-release,参考我们的文章

在 gitlab ci 中运行以下命令检测当前提交是否符合 conventional-changelog 规范:

npx -p "@commitlint/cli" -p "@commitlint/config-conventional" -p "commitlint-format-junit" commitlint -x @commitlint/config-conventional -o commitlint-format-junit -f ${CI_COMMIT_BEFORE_SHA} > commitlint_result.xml

将 lint result 输出为 JUnit 格式,方便 Gitlab 在 merge request 的时候展示 lint 失败的结果。

vscode 用户

可以安装vscode-commitizen插件,使用ctrl+shift+pcommand+shift+p使用conventional commit提交代码。

image.png
image.png

这里快速总结一下本文的工具部分的安装和使用

基本安装和使用

# 安装git-cz包
npm install -g git-cz

# 以后所有使用git commit的地方都用git-cz或git cz命令提交代码
git cz [-a] [--amend] [...]

commitlint 验证是否符合规范

# 安装commitlint命令行和验证使用的规则config-conventional
npm install -g @commitlint/config-conventional @commitlint/cli

# 添加全局默认配置,以后commitlint命令都不用加 -x "@commitlint/config-conventional"
echo "module.exports = {extends: ['@commitlint/config-conventional']}" > ~/commitlint.config.js

# 验证最新一条提交记录(必须添加上述配置,否则需要加上 -x "@commitlint/config-conventional")
commitlint -e

git hook 自动验证

NodeJS 项目直接使用 husky:

npm install -D husky

然后在package.json添加 husky 配置:

{
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -x @commitlint/config-conventional -E HUSKY_GIT_PARAMS"
    }
  }
}

其他项目可以手工添加 git hook。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK