Git-如何写好一条提交信息

Git-如何写好一条提交信息

本文为翻译文章
原文: How to Write a Git Commit Message
作者: cbeams

1.为什么好的提交信息很重要

如果你曾经打开过任意一个Git仓库的提交历史,你可能会发现它们的提交信息多多少少会有些混乱。
请比较下面两个提交历史:

$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009"

e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.
2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)
147709f Tweaks to package-info.java files
22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils
7f96f57 polishing
$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"

5ba3db6 Fix failing CompositePropertySourceTests
84564a0 Rework @PropertySource early parsing logic
e142fd1 Add tests for ImportSelector meta-data
887815f Update docbook dependency and generate epub
ac8326d Polish mockito usage

上面两个提交历史其实是同一个仓库不同时期的提交记录,你可以从上面命令中的时间参数看得到。

那么,你更喜欢哪一个呢?

前者的长度和格式各不相同,后者则简洁一致。

前者是默认情况下发生的情况,后者绝不是偶然发生的。

虽然很多存储库的提交信息看起来像前者,但也有例外,比如Linux内核和 Git 本身就是很好的例子。

这些库的贡献者们知道,精心设计的提交信息是向其他开发人员(以及他们未来的自己)传达有关更短上下文的最佳方式。 diff 会告诉你发生了什么变化,但只有提交信息才能正确地告诉您原因。Peter Hutterer 很好地说明了这一点:

重新建立一段代码的上下文是浪费的。我们无法完全避免它,所以我们应该努力尽可能减少它。提交信息正好可做到这一点,因此,提交信息显示开发人员是否是一个好的协作者。

如果你还没用考虑过什么是好的Git提交信息,可能是因为你没有花太多时间使用git log 和相关工具。 这里有一个恶性循环:因为提交历史是非结构化和不一致的,人们不会花太多时间使用或维护它,因为它未得到好的使用和维护,它仍旧是非结构化和不一致的。

但是精心设计和维护提交信息是一件美好而有用的事。git blamerevertrebaselogshortlog 以及其它子命令将因此而栩栩如生。审查他人的提交记录以及PR/MR成为一件值得做得事情,并且突然可以独立完成。了解为什么几个月或几年前发生的事不仅变成可能的而且是有效的。

一个项目的长期成功取决于其可维护性,对于维护者来说,没有比项目日志更强大的工具了。这意味着我们值得花时间去学习如何维护日志。起初可能会有点麻烦,但很快将它编程习惯后,它将成为所有参与者的骄傲和效率之源。

在这篇文章中,我只讨论保持良好的提交历史的基本要素:如何编写单独的提交信息。还有其他重要的实践,比如【提交合并】,我不会在这里介绍。也许会在下一篇文章中来介绍。

2. 提交信息的最佳实践

大多数编程语言对于惯用风格都有完善的约定,即命名、格式等。当然,这些约定有多种变化,但大多数开发人员都同意,选择这些约定中的一个并坚持它,比每个人都按自己的习惯做事所带来的混乱来说要好得多。

同样地,一个团队处理提交信息的方法应该没有什么不同。为了创建有用的修订历史,团队应该首先就提交信息约定达成一致,该约定至少定义以下三件事:

  • 风格。 标记语法、换行边距、语法、大写、标点符号。 把这些事情说清楚,消除猜测,让一切尽可能简单。最终结果将是一个非常一致的日志,这不仅是一种阅读的乐趣,而且实际上确实可以定期阅读。

  • 内容。 提交信息的正文(如果有的话)应该包含什么样的信息,它不应该包含什么。

  • 元数据。 应该如何引用问题跟踪ID,MR请求编号等。

幸运地是,对于什么是管用的Git提交信息,有完善的约定。事实上,它们中的许多都是以某些Git命令的运行方式假设的。您无需重新发明任何东西。只需遵循以下七项规则,您就可以写出像专业人士一样的提交信息。

写好Git提交信息的七条规则

  1. 使用空行将标题与正文分割开
  2. 将标题字数限制为50个字符
  3. 大写标题行(对于英文)
  4. 不要以句号结束标题行
  5. 在标题中使用祈使句
  6. 正文在72个字符处换行
  7. 用正文解释是什么、为什么、怎么做

例如:


Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789
1. 使用空行分割标题和正文

虽然不是必需的,但最好以一个简短的(少于50个字符)行总结更改,,然后是一个空行,然后是更全面的描述。提交信息中第一个空行的文本被视为提交标题,并且该标题在整个Git中使用。例如,Git-format-patch(1) 将提交转换为电子邮件,它使用主题行上的标题和正文中提交的其余部分。 —— git commit 主页

首先,不是每个提交都需要一个标题和一个正文。有时一行就可以了,特别是当更改非常简单,不需要进一步的上下文时。例如:


	修复用户指引中介绍的拼写错误

无需多言,如果读者想知道错字是什么,他可以简单地查看更改本身,即,使用git showgit diffgit log -p

如果在命令行中提交类似的内容,那么使用 -m 选项进行git 提交很容易:

	$ git commit -m "修复用户指引中介绍的拼写错误"

然而,当提交需要一些解释和上下文时,您需要编写一个正文。例如:

	对主控程序进行分解
	
	
	MCP 原来是邪恶的,并已成为统治世界的意图。此提交将 Tron 的光盘放入 MCP(导致其解散)
	并把它变回国际象棋游戏

使用 -m 选项编写带有正文的提交信息并不容易。您最好在适当的文本编辑器中编写消息。如果您还没有在命令行中设置用于Git 的编辑器,请阅读 Pro Git 的这一部分

在任何情况下,在浏览日志时,标题与正文的分离都是值得的。以下是完整的日志条目:

	$ git log
	commit 42e769bdf4894310333942ffc5a15151222a87be
	Author: Kevin Flynn <[email protected]>
	Date:   Fri Jan 01 00:00:00 1982 -0200

	对主控程序进行分解
	
	
	MCP 原来是邪恶的,并已成为统治世界的意图。此提交将 Tron 的光盘放入 MCP(导致其解散)
	并把它变回国际象棋游戏

此时,git log --oneline 的输出将会是这样:


	$ git log --oneline
	42e769 对主控程序进行分解

或者,git shortlog,按用户分组提交,再次仅显示主题行以供简洁:


Kevin Flynn (1):
      对主控程序进行分解

Alan Bradley (1):
      Introduce security program "Tron"

Ed Dillinger (3):
      Rename chess program to "MCP"
      Modify chess program
      Upgrade chess program

Walter Gibbs (1):
      Introduce protoype chess program

在 Git 中有许多其他上下文,其中标题行和正文之间的区别开始发挥作用——但如果没有空白行,它们都不能正常工作。

2. 标题字数限制为50个字符

50 个字符不是硬性限制,只是一个经验法则。 保持这个长度的主题行确保它们可读,并迫使作者思考一下最简洁的方式来解释正在发生的事情

提示: 如果你很难总结,你可能一次提交了太多的更改。 争取原子提交

GitHub的UI完全了解这些约定。如果超过50个字符的限制,它将警告您:

Git-如何写好一条提交信息_第1张图片

并且将用省略号截断长度超过72个字符的任何内容行:

Git-如何写好一条提交信息_第2张图片

所以你可以书写50个字符,但是72个是硬限制。

3. 标题行大写

这听起来很简单,所有的标题行都已大写紫米开头。

例如,使用:

  • Accelerate to 88 miles per hour

代替:

  • accelerate to 88 miles per hour
4. 不要用句号结束标题行

标题行不需要尾随标点符号。此外,当你视图将它们保持在50个字符或更少时,空间是宝贵的。

例如,使用:

  • Open the pod bay doors

代替

  • Open the pod bay doors.
5. 在标题中使用祈使句

祈使句的意思就是“说的或写的,就像发出命令或指令一样”。几个例子:

  • 打扫你的屋子
  • 关闭这扇门
  • 将垃圾带出去

你现在正在阅读的七条规则中的每一个都是用祈使句编写的。(比如“正文在第72个字符处换行”)

祈使句听起来有点粗鲁——这就是为什么我们不经常使用它——但它非常适合Git提交的标题行。这样做的一个原因是:Git 本身在代表你创建提交时就是使用祈使句的:

	Merge branch 'myfeature'

或者当我们使用 git revert 时:


	Revert "Add the thing with the stuff"

	This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

或者当我们在GitHub上的一个MR请求中点击【合并】按钮时:

	
	Merge pull request #123 from someuser/somebranch

因此,当你使用祈使句编写提交信息时,你遵循的是Git自己的内置约定。 例如:

  • 重构子系统X,为了更好的可读性
  • 更新起始文档
  • 移除重复的方法
  • 发布 1.0.0 版本

这样写一开始可能有点尴尬。我们习惯于以指示性的语气说话,这都是关于报道事实的。这就是为什么提交消息常常以这样的方式结束阅读:

  • Fixed bug with Y
  • Changing behavior of X

有时, 提交信息被写为对其内容的描述:

  • More fixes for broken stuff
  • Sweet new API methods

为了消除任何混淆,这里有一个简单的规则,每次都正确:

格式正确的Git提交标题行应该始终能够完成以下句子:

  • 如果应用,此提交将是【你的标题行

例如:

  • 如果应用,这次提交将重构子系统X,为了更好的可读性
  • 如果应用,这次提交将更新起始文档
  • 如果应用,这次提交将移除重复的方法
  • 如果应用,这次提交将发布 1.0.0 版本
  • 如果应用,这次提交将合并PR#123,从user/branch 分支

注意,这对于其它非祈使句形式的形式是不起作用的:

  • 如果应用,这次提交将 修复Y 的 Bug
  • 如果应用,这次提交将 改变X的行为
  • 如果应用,这次提交将 更多的对于突发情况的修复
  • 如果应用,这次提交将 ~~~~ 可爱的新的API方法

记住: 只有在标题行中时,祈使句才重要,在正文中,可以放松这个限制。

6. 正文在第72个字符处换行

Git 不会自动换行文本。编写提交信息的正文时,必须注意其右边距,并手动换行。

建议使用 72 个字符,这样 Git 就有足够的空间缩进文本, 同时总体上仍保持在 80 个字符以下。

一个好的文本编辑器可以在这里提供帮助。例如,在编写Git 提交时,很容易将VIm配置为72个字符。然而,传统上,IDE 在为提交信息中的文本包装提供智能支持方面非常糟糕(尽管在最近的版本中,IntelliJIEDA 最终在这方面做得更好)。

7. 用正文来解释是什么、为什么和怎么做

比特币核心的提交 是一个很好的例子来解释改变了什么和为什么。

commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille <[email protected]>
Date:   Fri Aug 1 22:57:55 2014 +0200

   Simplify serialize.h's exception handling

   Remove the 'state' and 'exceptmask' from serialize.h's stream
   implementations, as well as related methods.

   As exceptmask always included 'failbit', and setstate was always
   called with bits = failbit, all it did was immediately raise an
   exception. Get rid of those variables, and replace the setstate
   with direct exception throwing (which also removes some dead
   code).

   As a result, good() is never reached after a failure (there are
   only 2 calls, one of which is in tests), and can just be replaced
   by !eof().

   fail(), clear(n) and exceptions() are just never called. Delete
   them.

看一看完整的差异,想想作者花时间在这里和现在提供的这个上下文,为同时和未来的提交者节省了多少时间。如果他不这样做,它可能会永远迷失。

在大多数情况下,您可以省略有关如何进行更改的详细信息。代码在这方面通常是不言自明的(如果代码太复杂以至于需要用散文来解释,这就是源注释的用途)。 只需专注于弄清楚你最初进行更改的原因——更改前的工作方式(以及其中有什么问题)、它们现在的工作方式以及你为什么决定按照你的方式解决问题。

将会感谢你现在工作的未来维护者可能就是你自己。

3. 提示

学会爱上命令行,将IDE抛在脑后

出于与 Git 子命令一样多的原因,使用命令行是明智之举。 Git 非常强大; IDE 也是如此,但每个都有不同的方式。 我每天都使用 IDE (IntelliJ IDEA) 并广泛使用其他 IDE (Eclipse),但我从未见过 Git 的 IDE 集成可以开始匹配命令行的易用性和强大功能(一旦您了解它)。

某些与 Git 相关的 IDE 功能是无价的,例如在删除文件时调用 git rm,在重命名文件时使用 git 执行正确的操作。 当您开始尝试通过 IDE 提交、合并、变基或进行复杂的历史分析时,一切都会崩溃。

当谈到使用Git的全部功能时,它始终是命令行。

请记住,无论您使用Bash、Zsh还是Powershell,都有一些制表符完成脚本,可以省去记住子命令和开关的许多麻烦。

你可能感兴趣的:(开发环境与工具,git,github)