绝对的说法都是错误的。

<译> Conventional Commits:一份让代码提交记录人机友好的规范

原文链接: https://www.conventionalcommits.org/en/v1.0.0/

注意:

  • Commit/Commit Message 有时候被翻译成了“代码提交”/“代码提交信息/记录”。
  • 为了与英文格式一一对应,type/scope/description/body 等尽量使用了原词或者进行了标注。

概要

Conventional Commits(约定俗成的提交)规范是一份针对代码提交信息的轻量级约定。这份规范提供了一组简单的规则用于创建一份明确的代码提交的历史记录,并且方便在此基础之上做一些自动化的工具。这份约定描述了代码提交中带来的功能特性、修复和不兼容性更改,与 SemVer(语义化版本)是相吻合的。

代码提交记录应该有如下结构:

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

为了交代清楚每次代码提交的意图,代码提交记录包含如下结构要素:

  1. fix: 此类型(type)的代码提交是对 BUG 的修复(对应 SemVer 里面 PATCH 版本变更)。
  2. feat: 此类型( type)的代码提交意味着添加了一个新的功能(对应 SemVer 里面的 MINOR 版本变更)。
  3. BREAKING CHANGE: 通过添加一个 BREAKING CHANGE: 的脚注或者在 类型/范围(type/scope)后面添加一个 ! 字符来表示一个不兼容的 API 变更(对应 SemVer 里面的 MAJOR 版本变更)。BREAKING CHANGE 可以是任何类型的代码提交的一部分。
  4. 除了 fix:feat: 类型之外的其它类型也是允许的,例如 @commitlint/config-conventional(基于 Angular Commit Message Guideline)就推荐使用 build:chore:cli:docs:style:refactor:perf:test: 等其它类型。
  5. BREAKING CHANGE: <description> 之外的其它脚注信息遵循 git trailer format 形式的约定。

非本规范强制使用的其它额外类型(type),在语义化版本(SemVer)中不会产生副作用(除非这些类型包含 BREAKING CHANGE)。

可以给相关类型的代码提交记录添加范围(scope),以提供额外的上下文信息。scope 放在圆括号里面。

例子

有基本描述( description)和 BREAKING CHANGE 脚注的代码提交记录:

feat: allow provided config object to extend other configs

BREAKING CHANGE: `extends` key in config file is now used for extending other config files

通过添加 ! 来指出不兼容性的更改:

refactor!: drop support for Node 6

既有 ! 又有 BREAKING CHANGE 脚注的例子:

refactor!: drop support for Node 6

BREAKING CHANGE: refactor to use JavaScript features not available in Node 6.

没有 body 块的示例:

docs: correct spelling of CHANGELOG

scope 的示例:

feat(lang): add polish language

有多段 body 和多个 footer(脚注) 的示例:

fix: correct minor typos in code

see the issue for details

on typos fixed.

Reviewed-by: Z
Refs #133

规范

这份文档中包含的关键字: “必须”、“不必”、“必要的/必选的”、“应该”、“不应该”、“推荐”、“可以” 以及 “可选的” 的意思和 RFC 2119 中描述的一致。

  1. 代码提交记录必须用一个名称类型的类型(type)字段作为前缀,例如 featfix 等,然后紧接着的是一个可选的范围(scope),可选的范围(scope)后面是一个可选的 !,然后后面接着的必须是一个冒号 : 加一个空格。
  2. 添加新功能特性的时候必须使用 feat 类型(type)。
  3. 修复 BUG 的时候必须使用 fix 类型(type)。
  4. 类型(type)后面可以提供一个范围(scope)。范围(scope必须是一个描述代码库某部分的名词,并且放在圆括号里面,比如 fix(parser):
  5. 描述(description必须紧接在 类型/范围(type/scope) 后面的冒号和空格之后。用于简明的描述代码变更,例如 fix: array parsing issue when multiple spaces were contained in string
  6. 更长的正文描述(body可以追加在简短的描述(description)之后,用于提供代码变更相关的额外上下文信息。bodydescription 之间必须用一个空行分隔。
  7. body 的格式是不受限制的,可以由多个段落组成。
  8. body 之后可以接一个空行,然后提供一个或者多个脚注(footer)。每个脚注 footer 必须由一个单词(word token)组成,紧接着的是 : <space> 或者 <space>#,然后接着一个句子 (这个格式受了 git trailer convention 启发)。
  9. 脚注(footer)最开始的单词(token)标记里的空格必须使用 - 替换,比如 Acked-by (这样的标记是为了和多段 body 区分开来)。BREAKING CHANGE 这种使用空格的方式是一个例外。
  10. 脚注(footer)的标记之后可以包含空格和新行,解析的时候必须使用上面描述的单词和分隔符来区分多个脚注条目。
  11. 不兼容性的更改必须在 类型/范围(type/scope)前缀里面用 ! 表明,或者在脚注(footer)添加一个条目。
  12. 如果把不兼容性的变更信息放在脚注(footer)里面,BREAKING CHANGE 必须大写,然后接一个冒号(:)加一个空格,再后面写上具体的描述,比如 BREAKING CHANGE: environment variables now take precedence over config files
  13. 如果想把不兼容的变更标记放在 类型/范围(type/scope)前缀里面,必须在紧挨着冒号 : 之前添加一个感叹号 !,即 !:。如果使用的是添加 ! 的方式,脚注里面可以省略不兼容变更的描述,但是 :<space> 之后必须包含不兼容变更的描述信息。
  14. 除了 featfix 之外的类型(type)也是可以使用的,比如 docs: updated ref docs
  15. 对于实现者而言, Conventional Commits 的各个组成部分不必是大小写敏感的,但是 BREAKING CHANGE 必须大写。(译注: 组成部分应该指的是 type/scope 以及脚注的 token。其它英文书写形式还是保持正常,比如大写表示强调等)
  16. 脚注(footer)中的单词标记 BREAKING-CHANGE 必须BREAKING CHANGE 是一个意思,不要赋予其它意义。

为什么要使用 Conventional Commits

  • 使用工具自动生成变更日志(CHANGELOG)。
  • 使用工具自动生成新的语义化版本号(SemVer)(基于上述的提交类型)。
  • 向同事、公众和其它利益相关者传达变更的性质。
  • 触发构建和发布流程。
  • 使大家更容易的给你的项目做出贡献,毕竟有更结构化的提交历史便于查览。

FAQ

  • 在开发的初始阶段怎么对待提交记录?

    我们建议你在任何时候都持一致的态度。通常会有不是开发者的其它人使用你的软件,他们会想知道哪些提交是已修复的、哪些是不兼容的,等等。

  • 类型(type)该大写还是小写?

    都可以,但是最好保持一致。

  • 如果一次提交包含多种类型(type)怎么办?

    尽可能将这次提交进行(重新)拆分。这份规范的好处是能驱使我们将代码提交和 PR 组织得井井有条。

  • 这份规范推荐快速开发和快速迭代吗?

    强烈不推荐以混乱的方式快速推进。长期来看,这份规范能让你在有多个贡献者的多个项目之中快速迭代。

  • Conventional Commits 是不是会将开发者的思维限制在已经提供的类型(type)之中?

    Conventional Commits 推荐我们自定义一些特定的类型 (type),同时,可以随着项目演进添加或者更改自定义的类型(type)。

  • 这份规范和语义化版本(SemVer)有什么关系?

    fix 类型的提交应该包含在 PATCH 版本里,feat 类型的提交应该被包含在 MINOR 版本里。包含 BREAKING CHANGE 的提交,不管什么类型都应该递增 MAJOR 版本号。

  • 我对这份规范进行扩展的版本该如何发布?

    我们推荐你使用语义化版本(SemVer)来发布你自己对这份规范的扩展(并且非常推荐你们自己做扩展!)。

  • 如果我使用了一个错误的类型(type)该怎么办?

    • 当你使用的是符合规定但是不正确的类型(type)时,例如使用 fix 错误的替代了 feat

      如果还没有发布或者合并的话,推荐使用 git rebase -i 来编辑提交历史。如果合并了,应该根据你使用的工具来决定如何来做清理。

    • 如果你使用了不符合规定的类型(type),例如使用的是 feet 而不是 feat

      即使是最坏的情况,不符合规范也不意味着世界末日。仅仅是不能被基于此规范的工具理解而已。

  • 我所有的贡献者都必须使用该规范吗?

    不用。如果你的 Git 工作流是基于 squash 的,那么核心维护者可以在合并提交的时候压缩清理这些提交记录,这样就没必要让偶尔才提交贡献的人在规范上花额外的时间和精力。一个比较普遍的流程是先使用自动化的手段来压缩提交信息,然后让核心维护者输入合适的 Git 提交信息。

  • 该规范怎么处理 revert 提交?

    回退代码的提交可能相对复杂:是回退多个提交记录吗?如果撤销的是一个功能特性,下一个版本应该是一个 PATCH 吗?

    Conventional Commits 没有提供明确的规范来定义 revert 行为,使用者用可以使用其它类型(type)或者脚注(footer)来处理这种情况。

    一个推荐的方式是使用 revert 类型(type),并且在脚注(footer)里面添加被回退的提交的引用(commit SHA):

    revert: let us never again speak of the noodle incident
    
    Refs: 676104e, a215868
    

关于

这份 Conventional Commits 规范受了 Angular Commit Guidelines 的启发,并且很多内容都是基于 Angular Commit Guidelines

其它

后面是一系列工具什么的,直接省略了,感兴趣的戳 https://www.conventionalcommits.org/en/v1.0.0/#about