写好 Git Commit 信息的 7 个建议

介绍: 为什么好的提交信息如此重要

当你随意浏览任一 git 仓库的日志,你很可能会发现其中的提交信息或多或少有点乱。举个例子,瞧一瞧我早先提交到 Spring 上的这些宝贝


  1. $ 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

狂吐吧!和最近提交到同一个仓库的信息比较一下:


  1. $ 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 自己都是很好的例子。Tim Pope 维护的仓库,以及 Spring Boot 也都不错。

这些仓库的贡献者知道,和后续开发者(事实上未来就是他们自己)沟通一个改动的上下文context,最好方法就是通过一个好的 git 提交信息。代码差异diff可以告知改动的内容,但只有提交信息才能正确地告诉你为什么。Peter Hutterer 很好地指出了这一点:

重建一段代码的上下文是一种浪费。我们不能完全避免,我们只能努力尽最大可能去减少它。提交的信息就可以做到这一点,以至于一个提交信息可以表明一个开发者是不是一个好的合作者。

如果你对如何写好 git 提交信息没有仔细想过,那你很可能没有怎么使用过 git log 和相关工具。这里有一个恶性循环:因为提交的历史信息组织混乱而且前后矛盾,那后面的人也就不愿意花时间去使用和维护它。 又因为没有人去使用和维护它,提交的信息就会一直组织混乱和前后矛盾。

但一个好的日志是一个优美和有用的东西,一旦日志处理的好,那么 gitblamerevertrebaselog、 shortlog 和其它子命令都将发挥它们的作用。查看别人的提交和 pull 请求是值得的,而且可以随时独立完成。理解几个月或者几年前发生的代码变动不仅变得可能,而且高效。

一个项目的长期成功依赖于(除了其它方面)它的可维护性,一个维护者最有力的工具就是项目的日志。所以非常值得花时间学习如何正确地维护它。刚开始可能很麻烦,但很快会成为习惯,最终会成为人们自豪和生产力的源泉。

我在这篇文章只会讨论如何保持一个健康的提交历史的最基本要素:即如何写好个人的提交信息。其它重要的实践,比如 commit squashing,我在这里不会涉及。我可能会在后续文章里讨论这些。

对于什么是惯用的约定,即命名和格式等,大多数编程语言都已经形成惯例。这些约定千差万别,但是大多数开发者都同意选择一种并坚持下去,这比让每个人自行其事导致混乱要好得多。

一个团队提交日志的方法应该一致 。为了创建一个有用的修改历史,团队应该首先对提交信息的约定形成共识,至少明确以下三件事情:

风格。包含句语、自动换行间距、文法、大小写、拼写。把这些讲清楚,不要让大家猜,并尽可能保持简单。最终的结果就是一份相当一致的日志,不仅让人读起来很爽,而且可以定期阅读。

内容。哪些信息应该包含在提交信息(如果有)的正文中?哪些不用?

元数据。如何引用问题跟踪 ID,pull 请求编号等?

幸运地是,如何生成一个地道的 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 consequenses 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 commit 帮助页:

虽然不是必须的,在提交的信息中先用一行简短的文字(少于50个字符)总结改动是好的想法,后面空一行就是更为详细的描述。提交信息中第一个空行前的文字可以作为题目,这个题目会在整个 Git 用到。比如,git-format-patch 把一个提交转化成 email,它就使用这个题目作为邮件的标题,提交中余下的部分作为邮件正文。

首先,不是每一个提交都需要标题和正文。有时简单一行也可以,特别是当这个改动很简单将来也不会变化。比如:


  1. Fix typo in introduction to user guide

不需要再多说什么了。如果读者想知道拼写错误具体是什么,她通过 git showgit diff 或者 git log -p 命令,就可以很容易地看到这个改动。

如果提交的信息像下面命令行那样简单,你可以在 git commit 时使用 -m 开关。


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

但如果一个 commit 需要多解释一点,你就要写一下正文。比如:

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 的这个章节

无论如何,在浏览日志时,你会发现把标题和正文分开是值得的。下面是完整的日志:


  1. $ git log
commit 42e769bdf4894310333942ffc5a15151222a87be
Author: Kevin Flynn <kevin@flynnsarcade.com>
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)

现在执行 git log –online,就只印出主题这行:


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

或者,git shortlog,按用户来归类提交信息,为了简洁一样也只显示标题。


  1. $ 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个字符不是一个硬性规定,只是一个经验之谈。把标题行限制在这个长度,既保证它们容易阅读,也强迫作者去思考如何用最精简的方式解释发生了什么。

小技巧:如果你发现很难总结,那你可能一次提交太多改动了。 争取作原子的提交(一个题目对应一个单独的提交)

GitHub 的界面充分考虑到这些约定。如果超过50个字符的限制,它会警告你:

gh1

标题行中超过69字符的部分都被会截断,显示为省略号:

gh2

所以目标是50个字符,但一定不要超过69个字符。

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 代表你创建一个提交时,它自己就是使用祈使语气。

例如,使用git merge 后的默认输出信息读起来就像:


  1. Merge branch 'myfeature'

当你使用 git revert 时:


  1. Revert "Add the thing with the stuff"
  2. This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

或者当在一个 GitHub  pull请求上点击“Merge”按钮时:


  1. Merge pull request #123 from someuser/somebranch

当你用祈使语气编写你的提交信息时,你遵守了 git 内在的约定。例如:

  • 重构 X 子系统以增加可读性
  • 更新新手入门的文档
  • 删除弃用的方法
  • 发布1.0.0版本

一开始这样写会有点尴尬。同样是用来描述事实,我们更习惯用陈述方式去讲话。这也就是为什么提交信息常常读起来都是这样:

  • 用 Y 修正了问题
  • X的改变行为

有时编写的提交信息像是一个内容的描述:

  • 对损坏事物的更多修正
  • 新酷的 API 方法

有一个简单的规则,每次把它做正确就可以减少误解。

一个格式正确的 git 标题行应该类似下面的句子:

如果被采用,这个 commit 将把你的标题放在这里

例如:

  • 如果被采用,这个 commit 将会重构 X 子系统以增加可读性
  • 如果被采用,这个 commit 将会更新新手入门的文档
  • 如果被采用,这个 commit 将移出弃用的方法
  • 如果被采用,这个 commit 将发布 1.0.0 版本
  • 如果被采用,这个 commit 将从 user/branch 合并 #123 pull 请求

注意下面这些非祈使格式不能工作:

  • 如果被采用,这个 commit 将用 Y 修正了问题
  • 如果被采用,这个 commit 将 X 的改变行为
  • 如果被采用,这个 commit 将对损坏事物的更多修正
  • 如果被采用,这个 commit 将新酷的 API 方法

记住:使用祈使语气只在标题上是重要的。你在编写正文的时候,可以放宽这一限制。

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

Git 从来不自动换行。当你编写一个提交信息的正文时,你必须考虑到正确的间距和手动换行。

推荐在72个字符处换行,这样 git 有足够的空间来缩进文本,还可以保持整体都在80个字符以内。

一个好的编辑器在这里可以有所帮助。例如当你编写一个 git 提交时,可以很容易在 Vim 上设定 72 个字符换行。但是通常,IDE 提供文本换行的智能支持都很糟糕(虽然在最近版本中,IntelliJ IDEA终于有所改善)。

7. 使用正文解释是什么和为什么,而不是如何做

这个提交是一个来自 Bittcoin Core 的好例子,解释了什么被改动了和为什么:


  1. commit eb0b56b19017ab5c16c745e6da39c53126924ed6
  2. Author: Pieter Wuille <pieter.wuille@gmail.com>
  3. Date: Fri Aug 1 22:57:55 2014 +0200
  4. Simplify serialize.h's exception handling
  5. Remove the 'state' and 'exceptmask' from serialize.h's stream
  6. implementations, as well as related methods.
  7. As exceptmask always included 'failbit', and setstate was always
  8. called with bits = failbit, all it did was immediately raise an
  9. exception. Get rid of those variables, and replace the setstate
  10. with direct exception throwing (which also removes some dead
  11. code).
  12. As a result, good() is never reached after a failure (there are
  13. only 2 calls, one of which is in tests), and can just be replaced
  14. by !eof().
  15. fail(), clear(n) and exceptions() are just never called. Delete
  16. them.

看一下完整的 diff,可以想象作者当下花了多少时间提供这些上下文信息,这大大节省了同伴和未来提交者的时间。如果他不这么做,这些信息可能就永远消失了。

大多数情况下,你可以省去改动的具体实现细节。 在这点上,代码通常是不需加以说明的(如果代码太复杂需要文字解释,可以使用代码注释)。首先把你做这个改动的原因交待清楚 —— 改动前是如何工作的(和出了什么问题),现在是如何工作的,以及为什么你要采用这种方法解决问题。

未来的维护者会感谢你,这个人可能就是你自己!

小技巧

学着去热爱命令行,抛弃 IDE

拥抱命令行是明智的,理由就像 git 子命令那样多。Git 是强大的,IDE 也是,但是表现的方式不同。我每天都使用 IDE (IntelliJ IDEA),也用过不少其它的IDE(Eclipse),但我看到集成 git 的IDE ,都无法企及命令行的方便和强大(一旦你了解它)。

某些 git 相关的 IDE 功能是很有用的,比如通过调用git rm 删除一个文件,用 git 重新命名一个文件。但一旦你开始使用 commitmergerebase 这些命令,或者进行复杂的历史分析,IDE 就无能为力了。

要发挥 git 的全部火力,那就是命令行。

记住无论你使用 Bash 还是 Z shell,都可以使用 Tab 补齐脚本来减轻记住子命令和开关的痛苦。

本文来自合作伙伴“Linux中国”,原文发布日期:2015-10-14   

时间: 2024-09-01 15:08:31

写好 Git Commit 信息的 7 个建议的相关文章

Git commit 信息标准和丢弃必须要的commit

/***************************************************************************** * Git commit 信息标准和丢弃必须要的commit * 说明: * 提交commit信息需要相对来说详细一点,同时经常会需要剔除一些commit. * * 2017-5-19 台湾 中和区 曾剑锋 *******************************************************************

02_创建Git仓库,克隆仓库,git add,git commit,git push,git pull,同行冲突,不同行冲突的结局方案,git mergetool的使用

1 创建Git资源库,残酷目录信息 创建git资源库的命令: git init –bare 仓库名称 (其中-bare表示的意思是空的库的意思) 进入E:\software\repository\git\itheima28,截图如下: hooks:提交一些脚本文件 info:存放一些个人信息,配置信息 objects:所有数据存放位置 refs:git指针信息,记录了修改了什么等的信息 config:核心的配置信息 description:描述信息 HEAD:存放的分支信息. 2 使用上面创建的

Spring Boot中使用Actuator的/info端点输出Git版本信息

对于Spring Boot的Actuator模块相信大家已经不陌生了,尤其对于其中的/health./metrics等强大端点已经不陌生(如您还不了解Actuator模块,建议先阅读<Spring Boot Actuator监控端点小结>).但是,其中还有一个比较特殊的端点/info经常被大家所忽视,因为从最初的理解,它主要用来输出application.properties配置文件中通过info前缀来定义的一些属性,由于乍看之下可能想不到太多应用场景,只是被用来暴露一些应用的基本信息,而基本

git学习------&amp;gt;git commit命令的默认编辑器的修改

   今天在新同事的电脑上,用git commit命令帮新同事提交代码的时候,编辑完commit的信息后,居然不记得怎么退出了.蛋疼. 后来百度了一下,原来此时是进入GUN nano编辑器.在这里可以添加你的commit imformation 然后ctrl+o,回车保存,再ctrl+x退出.好吧,我完全不习惯,因为我电脑上配置的默认编辑器是VIM.         现在把git commit的编辑器改回到VIM. 方法一.直接敲命令:git config –global core.editor

jqueryajax-jquery写按钮删除员工信息请求

问题描述 jquery写按钮删除员工信息请求 这个按钮触发不了删除事件,求指教呀. 解决方案 你的删除方法中的checked是哪来的? 你把tr加个id 传到删除按钮的onclick方法里就可以了 解决方案二: 通过dom关系获取 $('.delete').click(function(){ var tr=$(this).closest('tr')//被点击按钮所在行 //.....其他代码 })

java 调用 rest 接口 怎么写请求行的信息?

问题描述 java 调用 rest 接口 怎么写请求行的信息? Rest接口格式:每一个请求通常由三部分组成:请求行.请求报头.请求正文(可选). 请求样例: Post /services/ita/login HTTP/1.1 Host: https://: Accept:application/json;charset=UTF-8;Content-Type:application/json; charset=UTF-8 Accept-Language:zh_CN X-Auth-User:use

Xcode使用Git commit出错

问题描述 Xcode使用Git commit出错 不知道是什么原因,跪求大神解答 解决方案 Xcode中使用Git如何修改git commit所使用的编辑器为vim初次使用git commit报错问题 解决方案二: 你软件安装时,没有任何问题吧?如果有些库没有安装配置成功可能会出现状况 解决方案三: 是不是缺少依赖的库呀?你仔细检查检查 解决方案四: 如果你是盗版的Xcode不要随便改动内部代码,申请个苹果号,到官网上下个正版的,反正免费

用ASP.Net写一个发送ICQ信息的程序代码

asp.net|程序 这里我给大家提供一个很实用的例子,就是在线发送ICQ信息.想一想我们在网页上直接给朋友发送ICQ信息,那是多么美妙的事情啊.呵呵,在吹牛啊,其实ICQ本来就有在线发送的代码,不过,这些都是AOL给你写好的代码,多没有意思啊.还是自已写的比较好,呵呵,废话少说,大家来看代码吧. <% @ Page Language="C#" %><% @ Assembly Name="System.Net" %><% @ Impor

写给Git初学者的7个建议

当我刚刚开始使用Git的版本控制时,我根本不确定我付出那么多时间是不是会得到回报.Branch.Stage.Stash,这些Git名词对我来说都非常陌生. 而今天的我已不能想象生活没有Git会变成什么样.Git不仅提供了我非常需要的版本控制功能,还让我变成一个更优秀的程序员. 这里有一系列可以帮助你的小贴士,可以让Git成为你开发工作中非常重要的一部分.   第一条:花时间去学习Git的基本操作 学习Git的基本操作并不是要求你把整个Git文档从头到尾读完(但如果这就是你的方式,我也不会反对).