1. Commit message格式
每次提交,Commit message 都包括三个部分:Header,Body 和 Footer。
bash<type>(<scope>): <subject> // 空一行 <body> // 空一行 <footer>
其中,Header 是必需的,Body 和 Footer 可以省略。
不管是哪一个部分,任何一行都不得超过72个字符(或100个字符)。这是为了避免自动换行影响美观。
你可以为 git 设置 commit template,(也可以用工具来生成,见后面2.2 commit message编写工具),每次 git commit 的时候在 vim 中带出, 时刻提醒自己:
修改 ~/.gitconfig, 添加:
text
[commit]
template = ~/.gitmessage
新建 ~/.gitmessage 内容可以如下:
text
# head: <type>(<scope>): <subject>
# - type: feat, fix, docs, style, refactor, test, chore
# - scope: can be empty (eg. if the change is a global or difficult to assign to a single component)
# - subject: 动宾结构,25字以内,可以中文
#
# body: 36个字每行. 可以中文描述:
# * 为什么这次修改是必须的?
# * 它是怎么解决这个问题的?
# * 有没有其他副作用?
#
# footer:
# - 是否包含相关issue,例如 fix #12341.
# - 是否为BREAKING CHANGE: 对外变更等,都需要在这儿描述,例如
# BREAKING CHANGE: 对外API发生变更
# 以前的API是什么样的,现在API是什么样的
1.1 Header
Header部分只有一行,包括三个字段:type(必需)、scope(可选)和subject(必需)。
(1)type
type用于说明 commit 的类别,只允许使用下面7个标识。
- feat:新功能(feature)
- fix:修补bug
- docs:文档(documentation)
- style: 格式(不影响代码运行的变动)
- refactor:重构(即不是新增功能,也不是修改bug的代码变动)
- test:增加测试
- chore:构建过程或辅助工具的变动
如果type为feat和fix,则该 commit 将肯定出现在 Change log 之中。其他情况(docs、chore、style、refactor、test)由你决定,要不要放入 Change log,建议是不要。
(2)scope
scope用于说明 commit 影响的范围,比如数据层、控制层、视图层等等,视项目不同而不同。
(3)subject
subject是 commit 目的的简短描述,不超过50个字符。
- 以动词开头,使用第一人称现在时,比如
change,而不是changed或changes- 第一个字母小写
- 结尾不加句号(
.)
1.2 Body
Body 部分是对本次 commit 的详细描述,可以分成多行。下面是一个范例。
bashMore 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
有两个注意点。
(1)使用第一人称现在时,比如使用change而不是changed或changes。
(2)应该说明代码变动的动机,以及与以前行为的对比。
1.3 Footer
Footer 部分只用于两种情况。
(1)不兼容变动
如果当前代码与上一个版本不兼容,则 Footer 部分以BREAKING CHANGE开头,后面是对变动的描述、以及变动理由和迁移方法。
bashBREAKING 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.
(2)关闭 Issue
如果当前 commit 修复某个issue,那么可以在 Footer 部分修复这个 issue 。
bashfix #234
也可以一次关闭多个 issue 。
bashfix #123, #245, #992
1.4 Revert
还有一种特殊情况,如果当前 commit 用于撤销以前的 commit,则必须以revert:开头,后面跟着被撤销 Commit 的 Header。
bashrevert: feat(pencil): add 'graphiteWidth' option This reverts commit 667ecc1654a317a13331b17617d973392f415f02.
Body部分的格式是固定的,必须写成This reverts commit <hash>.,其中的hash是被撤销 commit 的 SHA 标识符。
如果当前 commit 与被撤销的 commit,在同一个发布(release)里面,那么它们都不会出现在 Change log 里面。如果两者在不同的发布,那么当前 commit,会出现在 Change log 的Reverts小标题下面。
2 commit message相关工具
2.1 npm安装
bashapt-get install npm sudo npm install -g n sudo n latest sudo npm install -g npm hash -d npm npm -i
2.2 commit message编写工具
Commitizen是一个撰写合格 commit message 的工具。
安装命令如下。
bash$ npm install -g commitizen
然后,在项目目录里,运行下面的命令,使其支持 Angular 的 Commit message 格式。
bash$ commitizen init cz-conventional-changelog --save --save-exact
以后,凡是用到git commit命令,一律改为使用git cz。这时,就会出现选项,用来生成符合格式的 Commit message。
2.3 commit message校验工具
validate-commit-msg 用于检查 Node 项目的 Commit message 是否符合格式。
bash$ sudo npm install --save-dev validate-commit-msg $ node_modules/.bin/validate-commit-msg "$(git log -1 --pretty=%B)"
2.4 commit message转换为changelog工具
如果你的所有 Commit 都符合 Angular 格式,那么发布新版本时, Change log 就可以用脚本自动生成。
生成的文档包括以下三个部分。
- New features
- Bug fixes
- Breaking changes.
每个部分都会罗列相关的 commit ,并且有指向这些 commit 的链接。当然,生成的文档允许手动修改,所以发布前,你还可以添加其他内容。
conventional-changelog 就是生成 Change log 的工具,运行下面的命令即可。
bash$ npm install -g conventional-changelog-cli $ cd my-project $ conventional-changelog -p angular -i CHANGELOG.md -w
上面命令不会覆盖以前的 Change log,只会在CHANGELOG.md的头部加上自从上次发布以来的变动。
如果你想生成所有发布的 Change log,要改为运行下面的命令。
bash$ conventional-changelog -p angular -i CHANGELOG.md -w -r 0
为了方便使用,可以将其写入package.json的scripts字段。
javascript{ "scripts": { "changelog": "conventional-changelog -p angular -i CHANGELOG.md -w -r 0" } }
以后,直接运行下面的命令即可。
bash$ npm run changelog
3 commit message指导原则
3.1 结构变化
创建良好提交的基本规则是确保每个提交只有一个"逻辑更改"。这是一条重要规则的原因有很多:
- 更改的代码量越少,复查和识别潜在缺陷的速度就越快越容易。
- 如果以后发现更改存在缺陷,则可能有必要还原损坏的提交。如果没有其他不相关的代码更改与原始提交纠缠在一起,则这样做更容易。
- 当使用Git的bisect功能对问题进行故障排除时,定义明确的小变化将有助于准确地找出引入代码问题的位置。
- 当使用Git注释/责备浏览历史记录时,定义明确的微小更改也有助于准确隔离代码的来源和原因。
3.2 创建提交时应避免的事情
考虑到这一点,有一些经常遇到的不好的事情要避免的例子
- 将空白更改与功能代码更改混合在一起。
空格更改将掩盖重要的功能更改,从而使审阅者更难正确地确定更改是否正确。 解决方案:创建2个提交,一个提交带有空白更改,一个带有功能更改。通常,将首先进行空白更改,但这并不是硬性规定。
- 混合两个不相关的功能更改。
同样,如果将两个不相关的更改混合在一起,那么审阅者将更难发现缺陷。如果以后有必要还原损坏的提交,则这两个无关的更改将需要进行处理,从而进一步增加了错误创建的风险。
- 在一次大型提交中发送大型新功能。
很可能只有当所有新功能都存在时,新功能的代码才有用。但是,这并不意味着应在单个提交中提供整个功能。新功能通常需要重构现有代码。非常需要在与实现新功能的提交分开的提交中进行任何重构。这可以帮助审阅者和测试套件验证重构是否具有无意的功能更改。即使是新编写的代码,也经常可以分为多个部分,可以独立进行检查。例如,添加新的内部API /类的更改可以在独立的提交中进行。再次,这使得代码审查更加容易。如果还没有立即准备好合并新功能,则它还允许其他开发人员精挑细选工作的一小部分。应该在与实际内部实现分开的提交中添加新的公共HTTP API或RPC接口。这将鼓励作者和审阅者考虑通用的API / RPC设计,而不是简单地选择一种对其当前选择的内部实现更容易的设计。
遵循的基本规则是
如果可以将代码更改拆分为一系列补丁/提交,则应将其拆分。少即是不是更多。更多就是更多。
3.3 提交消息中的信息
与更改内容一样重要的是描述更改的提交消息的内容。编写提交消息时,需要记住一些重要的事情
- 不要以为审阅者理解最初的问题是什么。
在阅读错误报告时,经过多次来回评论后,问题的根本原因通常像泥泞一样清晰。提交消息应清楚说明原始问题是什么。该错误仅是有关/如何/发现问题的有趣历史背景。无需阅读错误凭单,就应该有可能检查提议的补丁的正确性。
- 不要以为审阅者可以访问外部Web服务/站点。
在有人在火车/飞机/教练/海滩/酒吧中排查问题并浏览Git历史记录的6个月时间内,无法保证他们将有权访问在线错误跟踪器或在线蓝图文档。分布式SCM的一大进步是,您不再需要"在线"就可以访问有关代码存储库的所有信息。提交消息应完全独立,以保持该优势。
- 不要认为代码是不言而喻的/自我证明的。
对于一个人来说,不言而喻的东西,对于另一个人来说,似乎是泥泞。始终记录最初的问题是什么以及如何解决,除了最明显的错别字或仅提交空白以外的任何更改。
- 描述*为什么要*进行更改。
一个常见的错误是仅记录代码的编写方式,而没有描述开发人员选择这样做的原因。一定要描述整体代码结构,尤其是对于较大的更改,但更重要的是描述更改背后的意图/动机。
- 阅读提交消息,看看它是否暗示改进的代码结构。
通常,在描述大型提交消息时,很明显,实际上应该将提交分为两部分或更多部分。不要害怕返回并重新设置更改基础,以将其拆分为单独的提交。
- 确保有足够的信息来决定是否进行审查。
当Gerrit发送电子邮件警报以提交新的补丁程序时,其中包含的信息很少,主要是提交消息和文件列表更改。鉴于补丁数量众多,期望所有审阅者都仔细检查补丁是不合理的。因此,提交消息必须包含足够的信息,以提醒潜在的审阅者以下事实:这是他们需要查看的补丁。
- 第一行提交是最重要的。
在Git提交中,提交消息的第一行具有特殊的意义。它用作电子邮件主题行,git注释消息,gitk查看器注释,合并提交消息以及更多空间有限的地方。除了总结更改本身之外,还应注意详细说明代码的哪些部分受到影响。例如,如果它影响libvirt驱动程序,请在第一行中提及" libvirt"。
- 描述当前代码的任何限制。
如果要更改的代码仍具有未来的改进范围,或者存在任何已知的限制,请在提交消息中提及这些限制。这向审阅者表明,已经考虑了更广泛的情况,并且在短期目标与长期愿望之间进行了权衡。
- 不包括特定于补丁集的注释。
换句话说,如果您要对更改进行重新设置,请不要在提交消息中添加"补丁集2:重新设置"。更改合并后,这将不再重要。但是,请务必在Gerrit中记录一下,以作为您所做更改的评论。它可以帮助审阅者了解补丁集之间的变化。这也适用于注释,例如"添加的单元测试","修复的本地化问题",或任何其他不影响提交总体意图的补丁集更改,例如补丁集更改。
要遵循的主要规则是:
提交消息必须包含完全理解和检查补丁程序的正确性所需的所有信息。少即是不是更多。更多就是更多。