让你的 commit 更有价值

一个持续更新的github笔记,连接地址:Front-End-Basics,本文地址:让你的 commit 更有价值html


提交规范

AngularJS 在开发者文档中关于 git commit 的指导说明,提到严格的 git commit 格式规范能够在浏览项目历史的过程当中看到更易读的信息,而且能用 git commit 的信息直接生成 AngularJS 的 change log 。node

commit messages 格式规范

commit messages 由 headerbodyfooter 组成。webpack

header 又包含 typescopesubjectheader 是必需的,不过其中的 scope 是可选的。git

bodyfooter 能够省略。github

<type>(<scope>): <subject>
// 空行
<BLANK LINE>
<body>
// 空行
<BLANK LINE>
<footer>
注:为了能在 github 以及各类 git 工具中看得更清晰,commit messages 的每一行都不要超过 100 个字符。

Header

Type

类型必须是如下几种之一:web

  • feat: 新功能
  • fix: bug 修复
  • docs: 仅修改文档
  • style: 修改格式(空格,格式化,省略分号等),对代码运行没有影响
  • refactor: 重构(既不是修 bug ,也不是加功能)
  • build: 构建流程、外部依赖变动,好比升级 npm 包、修改 webpack 配置等
  • perf: 性能优化
  • test: 测试相关
  • chore: 对构建过程或辅助工具和库(如文档生成)的更改
  • ci: ci 相关的更改

除此以外,还有一个特殊的类型 revert ,若是当前提交是为了撤销以前的某次提交,应该用 revert 开头,后面加上被撤销的提交的 header,在 body 中应该注明: This reverts commit <hash>. ,hash 指的就是将要被撤销的 commit SHA 。express

// 例如

revert: feat(user): add user type

This reverts commit ca16a365467e17915f0273392f4a13331b17617d.

Scope

scope 能够指定提交更改的影响范围,这个视项目而定,当修改影响超过单个的 scope 时,能够指定为 *npm

Sbuject

subject 是指更改的简洁描述,长度约定在 50 个字符之内,一般遵循如下几个规范:json

  • 用动词开头,第一人称如今时表述,例如:change 代替 changedchanges
  • 第一个字母小写
  • 结尾不加句号(.)

Body

body 部分是对本地 commit 的详细描述,能够分红多行。api

subject 相似,用动词开头,第一人称如今时表述,例如:change 代替 changedchanges

body 应该说明修改的缘由和更改先后的行为对比。

Footer

footer 基本用在这两种状况:

  • 不兼容的改动( Breaking Changes ),一般用 BREAKING CHANGE: 开头,后面跟一个空格或两个换行符。剩余的部分就是用来讲明这个变更的信息和迁移方法等。
  • 关闭 Issue, github 关闭 Issue 的例子
// BREAKING CHANGE: 的例子
BREAKING CHANGE: isolate scope bindings definition has changed and
    the inject option for the directive controller injection was removed.

    To migrate the code follow the example below:

    Before:

    scope: {
      myAttr: 'attribute',
      myBind: 'bind',
      myExpression: 'expression',
      myEval: 'evaluate',
      myAccessor: 'accessor'
    }

    After:

    scope: {
      myAttr: '@',
      myBind: '@',
      myExpression: '&',
      // myEval - usually not useful, but in cases where the expression is assignable, you can use '='
      myAccessor: '=' // in directive's template change myAccessor() to myAccessor
    }

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



// Closes Issue 例子
Closes #2314, #3421

完整的例子

例一: feat

feat($browser): onUrlChange event (popstate/hashchange/polling)

Added new event to $browser:
- forward popstate event if available
- forward hashchange event if popstate not available
- do polling when neither popstate nor hashchange available

Breaks $browser.onHashChange, which was removed (use onUrlChange instead)

例二: fix

fix($compile): couple of unit tests for IE9

Older IEs serialize html uppercased, but IE9 does not...
Would be better to expect case insensitive, unfortunately jasmine does
not allow to user regexps for throw expectations.

Closes #392
Breaks foo.bar api, foo.baz should be used instead

例三: style

style($location): add couple of missing semi colons

查看更多例子

规范 commit message 的好处

  • 首行就是简洁实用的关键信息,方便在 git history 中快速浏览
  • 具备详实的 body 和 footer ,能够清晰的看出某次提交的目的和影响
  • 能够经过 type 过滤出想要查找的信息,也能够经过关键字快速查找相关提交
  • 能够直接从 commit 生成 change log
// 列举几个经常使用的 log 参数

// 输出 log 的首行
git log --pretty=oneline

// 只输出首行的 commit 信息。不包含 hash 和 合并信息等
git log --pretty=format:%s

// 查找有关“更新菜单配置项”的提交
git log --grep="更新菜单配置项"

// 打印出 chenfangxu 的提交
git log --author=chenfangxu

// 红色的短 hash,黄色的 ref , 绿色的相对时间
git log --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr)%Creset'

用工具实现规范提交

上面介绍了规范提交的格式,若是让各位同窗在 git commit 的时候严格按照上面的规范来写,首先心智是有负担的,得记住不一样的类型究竟是用来定义什么的,subject 怎么写,body 怎么写,footer 要不要写。其次,对人的规范大部分都是反人性的,因此极可能在过不了多久,就会有同窗渐渐的不按照规范来写。靠意志力来控制本身严格按照规范来写是须要额外耗费一些精力的,把精力耗费在这种事情上面实在有些浪费。

用工具实现规范提交的方案,一种是在提交的时候就提示必填字段,另外一种是在提交后校验字段是否符合规范。这两种在实际项目中都是颇有必要的。

Commitizen

Zen-like commit messages for internet citizens. 嗯~~一种禅意

Commitizen 是一个帮助撰写规范 commit message 的工具。他有一个命令行工具 cz-cli,接下来会把使用 Commitizen 分红几个阶段来介绍。

体验 git cz

// 全局安装 Commitizen
npm install -g commitizen

你的仓库可能还不是对 Commitizen 友好的,此时运行 git cz 的效果跟 git commit 同样,也就是没有效果。 不过,能够执行 npx git-cz 来体验。

若是想直接运行 git cz 实现语义化的提交,能够根据 streamich/git-cz 文档中说的全局安装 git cz

// 全局安装 git cz
npm install -g git-cz

除此以外还有一种更推荐的方式,就是让你的仓库对 Commitizen 友好。

Commitizen 友好

全局安装 Commitizen 后,用 cz-conventional-changelog 适配器来初始化你的项目

// 初始化 cz-conventional-changelog 适配器
commitizen init cz-conventional-changelog --save-dev --save-exact

上面的初始化作了三件事:

  • 安装 cz-conventional-changelog 依赖
  • 把依赖保存到 package.json 的 dependenciesdevDependencies
  • 在根目录的 package.json 中 添加以下所示的 config.commitizen
"config": {
    "commitizen": {
      "path": "./node_modules/cz-conventional-changelog"
    }
  }

或者,在项目根目录下新建一个 .czrc 文件,内容设置为

{
  "path": "cz-conventional-changelog"
}

如今运行 git cz 效果以下:

cz-customizable 自定义中文配置

经过上面的截图能够看到,提交的配置选项都是英文的,若是想改为中文的,可使用 cz-customizable 适配器。

运行下面的命令,注意以前已经初始化过一次了,此次再初始化,须要加 --force 覆盖

npm install cz-customizable --save-dev

commitizen init cz-customizable --save-dev --save-exact --force

如今 package.json 中 config.commitizen 字段为:

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

cz-customizable 文档中说明了查找配置文件的方式有三种,咱们按照第一种,在项目根目录建立一个 .cz-config.js 的文件。按照给出的示例 cz-config-EXAMPLE.js 编写咱们的 config。 commit-type 能够参考 conventional-commit-types

能够点击查看我配置好的文件 qiqihaobenben/commitizen-git/.cz-config.js ,里面中详细的注释。

commitlint 校验提交

Commitizen 文档中开始就介绍到,Commitizen 能够在触发 git commit 钩子以前就能给出提示,可是也明确表示提交时对 commit messages 的校验也是颇有用的。毕竟即便用了 Commitzen,也是能绕过去,因此提交最后的校验很重要。

commitlint 能够检查 commit messages 是否符合常规提交格式,须要一份校验配置,推荐 @commitlint/config-conventional

npm i --save-dev @commitlint/config-conventional @commitlint/cli

在项目根目录建立 commitlint.config.js 文件并设置校验规则:

module.exports = {
  extends: ["@commitlint/config-conventional"],
  // rules 里面能够设置一些自定义的校验规则
  rules: {},
};

在项目中安装 husky ,并在项目根目录新建 husky.config.js 文件,加入如下设置:

// 安装 husky
npm install --save-dev husky


// husky.config.js 中加入如下代码
module.exports = {
  "hooks": {
    "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
  }
}
注意:由于 @commitlint/config-conventional 校验规则遵循 Angular 的规范, 因此咱们在用 cz-customizable 自定义中文配置时, 是按照给出的符合 Angular 规范的示例 cz-config-EXAMPLE.js 编写 .cz-config.js 的。可是若是你自定义的 Commitizen 配置不符合 Angular 规范,可使用 commitlint-config-cz 设置校验规则。(推荐仍是按照 Angular 规范进行 cz-customizable 自定义配置)
// 安装 commitlint-config-cz
npm install commitlint-config-cz --save-dev


// commitlint.config.js 改成
module.exports = {
  extends: [
    'cz'
  ]
};

git commit 触发 git cz

在提交的时候,咱们都习惯了 git commit ,虽然换成 git cz 不难,可是若是让开发者在 git commit 时无感知的触发 git cz 确定是更好的,
并且也能避免不熟悉项目的人直接 git commit 提交一些不符合规范的信息。

咱们能够在 husky.config.js 中设置:

"hooks": {
  "prepare-commit-msg": "exec < /dev/tty && git cz --hook || true",
}
注意: 在 window 系统,可能须要在 git base 中才能生效。

生成 CHANGELOG

standard-version
是一个使用 semverconventional-commits 支持生成 CHANGELOG 进行版本控制的实用程序。
standard-version 不仅是能生成 CHANGELOG , 还能根据 commit 的 type 来进行版本控制。

// 安装 standard-verison
npm i --save-dev standard-version

// 在 package.json 中的 scripts 加入 standard-version
{
  "scripts": {
    "release": "standard-version"
  }
}

示例项目

能够查看 commitizen-git ,里面概括了快速配置 Commitizen 友好仓库的步骤。
差很少三五分钟就能搞定。

能够看一下配置完后,执行 git commit 的效果。

扩展

更复杂的自定义提示

cz-customizable 中自定义配置项一般状况是够用的,
commitlint 中校验的规则基本上也是够用的,可是会有比较硬核的开发者会以为仍是不够,还要更多。好比一些 prompt 更加自定义,
提交时询问的 question 添加更多的逻辑,好比能够把一些重要的字段校验提早到 Commitizen 中,或者添加更多自定义的校验。

若是真想这么干,那就去 fork 一份 cz-conventional-changelog 或者 cz-customizable 来改,
或者直接本身写一个 adapter。

Commitizen 友好徽章

若是把仓库配置成了对 Commitizen 友好的话,能够在 README.md 中加上这个小徽章:Commitizen friendly

参考文档