How to Write a Git Commit Message

原文这里: https://chris.beams.io/posts/git-commit/, 只记录下关键内容。

The seven rules of a great Git commit message

举个例子:

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. 用空行把消息标题和消息内容分开

git 命令的帮助文档这么写:

Though not required, it’s a good idea to begin the commit message with a single short (less than 50 character) line summarizing the change, followed by a blank line and then a more thorough description. The text up to the first blank line in a commit message is treated as the commit title, and that title is used throughout Git. For example, Git-format-patch(1) turns a commit into email, and it uses the title on the Subject line and the rest of the commit in the body.

Firstly, not every commit requires both a subject and a body. Sometimes a single line is fine, especially when the change is so simple that no further context is necessary. For example:

首先,不是所有的提交信息都需要有消息标题和消息内容。有时候只有一行标题也是可以的。例如:

Fix typo in introduction to user guide

不用写过多的内容;如果看这个消息的人想要知道具体的 typo 是啥,他可以看看那个提交里面的包含的修改。使用 git showgit diffgit log -p 都可以。

如果你是从命令行提交这样的信息,可以使用 -m 参数:

$ git commit -m"Fix typo in introduction to user guide"

当然,如果一个提交里面包含需要说明的,你可以在消息内容里面包含更多信息。例如:

Derezz the master control program

MCP turned out to be evil and had become intent on world domination.
This commit throws Tron's disc into MCP (causing its deresolution)
and turns it back into a chess game.

包含消息内容的提交信息不太好用 -m 参数搞定。最好使用一个文本编辑器来做。如果你还没给命令行的 git 设置好编辑器,那可以去看看 Pro Git。

不管哪种情况,分开的好处会体现在浏览提交日志的时候。这里有个例子:

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

 Derezz the master control program

 MCP turned out to be evil and had become intent on world domination.
 This commit throws Tron's disc into MCP (causing its deresolution)
 and turns it back into a chess game.

使用 git log --oneline 只输出消息标题。

$ git log --oneline
42e769 Derezz the master control program

或者使用 git shortlog 针对提交用户分组,依然只显示消息标题。

$ git shortlog
Kevin Flynn (1):
      Derezz the master control program

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 个字符不是死限制,尽量控制到这个数量内来让消息标题更易读,同时也强迫写的人去思考如何更准确的描述发生了什么。

提示:如果你发现你总结起来比较费劲,那可能是因为你一次提交了太多内容了。尽量做到原子提交吧(不同话题分开提交)。

当超过 50 个字符的时候,GitHub UI 会提示你。

[图1]

会只显示 72 个字符加省略号。

[图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. 标题行里面使用祈使语气

祈使语气指的是说话或者写作就像是下命令或者指导一样。例子

Clean your room
Close the door
Take out the trash

这 7 条规则本身使用的就是祈使语气。

祈使语气听着会有点粗鲁,这也是为啥不常用的原因。但是这个用来做提交信息的标题栏很完美。一个原因就是 git 本身产生的一些提交里面使用的就是祈使语气。

例如, git merge 产生的默认提交信息如下:

Merge branch 'myfeature'

以及使用 git revert 的时候:

Revert "Add the thing with the stuff"

This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

或者在 GitHub 上面的 pull request 点击 Merge 按钮的时候:

Merge pull request #123 from someuser/somebranch

所以当你在自己的提交里面使用祈使语气的时候,其实也是跟随了 Git 的思路。例如:

Refactor subsystem X for readability
Update getting started documentation
Remove deprecated methods
Release version 1.0.0

这么写可能开始的时候会感觉有点尴尬。说话的时候使用祈使语气一般是用来汇报事实。这也是为什么阅读提交信息的时候一般会看到下面这样的情况:

Fixed bug with Y
Changing behavior of X

有些时候提交信息会是内容的描述:

More fixes for broken stuff
Sweet new API methods

这里有一个简单的规则。

一个好的 git 提交标题行总是可以很好的填入到下面的句式里面:

If applied, this commit will +your subject line here+

例如:

If applied, this commit will refactor subsystem X for readability
If applied, this commit will update getting started documentation
If applied, this commit will remove deprecated methods
If applied, this commit will release version 1.0.0
If applied, this commit will merge pull request #123 from user/branch

对于其他非祈使语气的例子就不太符合这个句式:

If applied, this commit will fixed bug with Y
If applied, this commit will changing behavior of X
If applied, this commit will more fixes for broken stuff
If applied, this commit will sweet new API methods

注意:只需要在提交消息标题行使用祈使语气。对于消息内容可以随意一点。

6. 提交信息内容每 72 个字符折行

Git 不会自动折行。当你提交的时候,需要自己设置好边缘,然后手动折行。

建议控制为 72 个字符,以便 git 有足够的空间处理缩进并保持所有行都在 80 个字符以内。

好的文本编辑器可以帮忙处理这个。vim 里面很容易配置当你在写提交信息的时候自动 72 个字符折行。然而传统上 IDE 们都做的比较差(不过在最近的一些版本里面 IntelliJ IDEA 做的比较好了)。

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.

看看这个提交,想想作者提交的上下文信息为其他维护人员和未来的维护人员省了多少时间。如果他没有写,很可能就永远丢失了。

大部分情况下,你可以不写变更是怎么做的。代码本身就是解释(如果代码确实比较复杂,那应该添加代码注释说明)。主要是说清楚为啥做这个变更,变更 以前是怎么个情况,以及有什么问题,现在是怎么个情况,以及你为啥用这样的方式解决。

未来的维护人员包括你自己都会很感谢你。