【翻译】如何编写 Git 提交消息

个人博客及创作索引页正在制作中,此处仅释出本地第一大版本。原文档基于 Hexo 及相关插件,不兼容于此处的格式暂不统一修复。

《【翻译】如何编写 Git 提交消息》[1]的简体中文翻译版本对应原文为 How to Write a Git Commit Message ,原作者为 Chris Beams 。请注意:

  • 正文格式尽可能与原网页保持一致;
  • 译者注将以脚注 (footnote) 的形式呈现,且其内容应以”译者注:”起始;
  • 原文中若有文内跳转超链接,如无必要,将直接去除,且不在译文中作进一步说明;
  • 原文中若有翻译后难以传达作者写作意图的词句 (通常是命令,或由源语言的特殊性质等原因导致) ,此时将不再翻译,且不在译文中作进一步说明。

翻译文本将从随后的分隔线开始展示。

如何编写 Git 提交信息

原作者: Chris Beams
原文创作日期: 2014 年 8 月 31 日

提交消息很重要。这里将展示如何写好它们。

【翻译】如何编写 Git 提交消息

引子:为什么好的提交消息很重要

如果你曾随意地浏览过一些 Git 仓库,你很可能会发现它们的提交消息或多或少有些杂乱。例如,你可以看看我早期提交给 Spring 的一些 Gem [2] 的日志:

$ 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 自身的源码正是良好的范例。或是看看 Spring Boot 或由 Tim Pope 管理的仓库。

这些仓库的贡献者们知道,一个经过精心打磨的 Git 提交消息是将一个更改与其他开发者 (以及未来的自己) 交流其 _来龙去脉_的最好方式[3]。一个 diff 的输出结果将告诉你 _什么_改变了,而只有提交消息能恰当地告诉你 _为什么_改变了。 Peter Hutterer 将这个观点表达得很好:

重新确定一段代码的上下文是浪费的。我们不能完全避免它,因此我们应当努力去[竭尽]所能减少这种情况的发生。提交消息能准确地做到这一点,所以 一条提交消息能够展示出一位开发者是不是好的协作者[4]

如果你还没有很多思路来编写良好的 Git 提交消息,这或许说明你没有花费很多时间使用 git log 命令和相关的工具。这里有一个残酷的循环:因为提交历史是缺少结构和一致性的,某个人不会花费很多时间使用或关心它。并且因为它不被使用或关心,它将始终缺少结构和一致性。

然而,被维护得很好的日志是一种优美和实用的东西,这会让 git blamerevertrebaselogshortlog 和其他子命令充满活力,会给回顾其他人的提交和 pull requests 带来一些价值——并且它们突然能被独立地完成。理解几个月或几年前一些事情为什么发生将不但变得可能,还将变得高效。

一个项目能否取得长远的成功 (相较于其他因素) 不但取决于其可维护性如何,还在于一个维护者是否没有多少比日志更加有力的工具了。我们值得花费一些时间来学习如何适切地维护项目的日志。起初维护日志时可能的困境不久就会转变为习惯,并最终成为所有参与者自豪感和生产力的源泉。

在这篇文章中,我将会告诉你保持一份健康的提交历史的最基础的要素:如何编写一条独立的提交消息。还有其他我在这里不会提及的重要习惯,比如说统整提交[5],或许我会在后续的投稿中谈到它们。

大多数编程语言都有着已经成形的惯例,它们构建了符合语言习惯的风格,就像命名、格式等等[6]。当然,这些惯例有诸多变种,但大部分开发者都认同专注于其中一种的情形远优于每个人各自选用一种造成的混乱局面。

一个团队对待提交日志的方式应当没有丝毫不同。为了创建一份实用的修订历史,团队应该首先在至少符合以下三点的提交消息惯例上达成共识:

风格。标记语言的句法[7],折行的间隔,语法[8],大小写,标点符号。将这些都明确给出,去除猜测,并且让一切都尽可能简单。最终的结果将会是一份格外一致的日志——不仅阅读起来很愉悦,而且实际上 的确能被定期阅读 [9]

内容。提交消息的主体 (如果有的话) 应该包含什么信息?什么是 _不能_包含的?

元数据。诸如 issue 的追踪编号[10]、 pull request 的编号应当如何被提及?

万幸的是,已经有一些成形的惯例来创建一条符合语言习惯的 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. 用一个空行分隔标题和主体

根据 git commit 命令的帮助页面

尽管不是必须的,一个好主意是,提交消息以一行简短的 (少于 50 个字符) 概括这个更改的文字为开始,紧接着是一个空行,随后是一段更详细的描述。整段文本的首行将被认作为提交的标题,那个标题将贯穿整个 Git [11] 。例如, Git-format-patch(1) 将提交转变为邮件,它将提交的标题作为邮件的主题,将剩余的提交内容作为邮件的主体。

首先,不是每一次提交都需要标题和主体。有时一行也很好,尤其是当更改很简单以至于进一步的阐释都不必要的时候。例如:

Fix typo in introduction to user guide

没有什么是需要解释的了。如果读者想知道这个拼写错误是什么,直接看这个更改本身即可,换句话说使用 git showgit diffgit log -p

如果你想用命令提交,给 git commit 命令添加 -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
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 中的其他上下文,它们的标题行和主体的区别被打破了——但它们都无法在二者之间不空行时做得合适[12]

2. 标题控制在 50 个字符以内

50 个字符不是硬性限制,只是一个经验法则。将标题行控制在这个长度能保证它们是可读的,并且能强迫作者花一些时间思考如何最简洁地解释将要发生什么。

提示:如果你难以概括你提交的内容,或许是因为你一次提交了太多的更改。努力做到原子级提交 [13] (另一篇投稿的话题) 吧。

GitHub 的用户界面全面地意识到了这些惯例。例如,它会在你的标题行超过 50 个字符时警告你:

【翻译】如何编写 Git 提交消息

并且会截断超过 72 个字符的标题行,后续用省略号代替:

【翻译】如何编写 Git 提交消息

因此,争取限制在 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 自身以你的名义创建提交时都是使用祈使语气

例如,使用 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 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 的配置很容易,例如在编写 Git 提交消息时在 72 个字符处折行。然而,在传统意义上, IDE 对于智能地支持提交消息的折行很糟糕 (尽管 IntelliJ IDEA 在最近的版本中终于 做得 比以前好了) 。

7. 用主体解释做了什么和为什么,而不是如何做到

这里的一条来自 Bitcoin Core 的提交 是解释更改了什么和为什么的最佳范例:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille
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.

看一看它的完整的 diff 信息,思考这位作者在此时此地花费时间提供代码的上下文节约了其他和未来的提交者多少时间。如果他没有做到,这次提交将很可能会永远被遗忘。

在大多数情况下,你可以省去这个更改如何被做出的细节。在这点上,代码通常能自我解释 (如果这段代码如此复杂以至于它需要用枯燥的语言来解释,那就是源代码注释应该做的事情了) 。只是专注于首先明确更改的原因——你在更改之前所做的事 (以及出现了什么错误) ,它们现在如何工作的,以及为什么你决定用你的方式解决这个问题[14]

未来感谢你的维护者可能就是你自己!

提示

学着热爱命令行。把 IDE 抛在脑后。

处于诸多原因,比如说 Git 子命令的存在,拥抱命令行是一种明智之举。 Git 有着令人疯狂的力量, IDE 亦然,但这两者体现在不同的方面上。我每天都使用一款 IDE (IntelliJ IDEA) ,也广泛地使用其他的 (Eclipse) ,但我还从没有见过哪款 IDE 的 Git 集成能比得上简单有力的命令行 (一旦你意识到了这点) 。

某些 Git 相关的 IDE 功能是无价的[^15],就像当你删除文件时执行 git rm ,在你重命名文件的时候用 git 执行正确的命令。而当你开始试着用 IDE 提交、合并、 rebase 或分析高深莫测的历史记录时,一切都会崩溃。

当支配 Git 的全部法力之日到来之时,一切都只剩下命令行。

记住不论你是使用 Bash 、 zsh 还是 PowerShell ,都有 Tab 自动补全 脚本来减轻不少记忆子命令和开关的痛苦。

阅读 Pro Git

Pro Git 在网上可以免费阅读,并且它很美妙。好好利用它吧!

题图提供者:xkcd

【完】

脚注

Original: https://www.cnblogs.com/littleye233/p/15173786.html
Author: 小叶Little_Ye
Title: 【翻译】如何编写 Git 提交消息

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/606362/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 离职,问题就解决了吗?

    刚入职场的那几年,我经常对工作有各种抱怨。回想起来,有两次冲动的不必要的离职,或者说应该干得更久一点。一旦有了离职的想法,整个人每天都纠结是去还是留,这种纠结成倍的放大焦虑,让自己…

    Linux 2023年6月6日
    0104
  • 良许跌宕起伏的2021年

    大家好,我是良许,前码农,现创业者。 时间飞逝,转眼就2021年年尾了,向各位「股东」们汇报一下良许的 2021 年。 公众号运营至今,每年我都会写年终总结,前三次总结给大家放在下…

    Linux 2023年6月14日
    0110
  • 【Linux】在Linux下文件io使用(二)

    在linux下,一切皆文件。当文件被打开时,会返回文件描述符用于操作该文件,从shell中运行一个进程,默认会有3个文件描述符存在(0、1、2); 0表示标准输入,1表示标准输出,…

    Linux 2023年6月13日
    0108
  • zabbix

    1. zabbix介绍 2. zabbix特点 3. zabbix配置文件 4. 部署zabbix zabbix介绍 zabbix是一个基于WEB界面的提供分布式系统监视以及网络监…

    Linux 2023年6月7日
    0157
  • Weblogic页面应用查询oracle数据库后台报错或页面日期格式显示错误

    问题:在生产环境中有两台WEB服务器,分别为227和228,部署的应用代码都是每日同步的,两边完全一致,但是某些页面查询数据时,227无结果,并且后台报java数组越界的错误,而2…

    Linux 2023年6月14日
    088
  • RPA SAP财务内部对账机器人

    bash;gutter:true;【简介】本机器人用于使用SAP软件的集团公司间往来对账前台登录SAP账户和密码,需退出PC微信,输入法切换为英文半角状态。【详细流程】1、清空Ex…

    Linux 2023年6月7日
    0118
  • Docker镜像构建之docker commit

    我们可以通过公共仓库拉取形象,但有时公共仓库拉取的形象不符合我们的需求。虽然我们已经从繁琐的部署工作中解脱出来,但在实际开发中,我们可能希望镜像包含整个项目的完整环境,将打包的完整…

    Linux 2023年5月27日
    088
  • MySQL双主同步的实现

    双主复制: 在两个节点上都可以写入数据,互为主从节点。 解决单点失败的问题:一个主节点失败,所有节点都会失败。 双主配置: (1) 各节点使用一个惟一server_id (2) 都…

    Linux 2023年6月7日
    088
  • DDR4 SDRAM -时序参数小册子

    如前所述,大神的原文链接如下:https://www.systemverilog.io/ddr4-timing-parameters-cheatsheet 参数 功能 ACTIVA…

    Linux 2023年6月7日
    096
  • Redis设置密码

    设置密码有两种方式。 运行cmd切换到redis根目录,先启动服务端 ><span class="hljs-selector-tag">red…

    Linux 2023年5月28日
    076
  • Docker 容器虚拟化

    Docker 容器虚拟化 1、虚拟化网络 Network Namespace 是 Linux 内核提供的功能,是实现网络虚拟化的重要功能,它能创建多个隔离的网络空间,它们有独自网络…

    Linux 2023年6月7日
    0125
  • 一篇文章带你全面读懂Android Backup

    前言 手机等智能设备是现代生活中的重要角色,我们会在这些智能设备上做登录账户,设置偏好,拍摄照片,保存联系人等日常操作。这些数据耗费了我们很多时间和精力,对我们而言极为重要。 如果…

    Linux 2023年6月13日
    0133
  • ASCLL 字符码

    信息在计算机上是用二进制数表示的,这种表示法让人很难理解。因此,计算机上都配有输入和输出设备,这些设备的主要目的就是以一种人类可阅读的形式将信息在这些设备上显示出来供人阅读理解。为…

    Linux 2023年6月7日
    097
  • n的阶乘前100项。Table of n! for n = 1..100

    n的阶乘前100项 {1,2,6,24,120,720,5040,40320,362880,3628800,39916800,479001600,6227020800,871782…

    Linux 2023年6月6日
    077
  • win的系统自动启动任务计划!!!

    posted @2022-04-19 16:56 钟小川 阅读(18 ) 评论() 编辑 Original: https://www.cnblogs.com/zhongxiaoch…

    Linux 2023年6月13日
    083
  • node-java的使用及源码分析

    上篇文章简单提了下node调用java的方法但也只属于基本提了下怎么输出helloworld的层度,这次将提供一些案例和源码分析让我们更好地了解如何使用node-java库。 前置…

    Linux 2023年6月14日
    097
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球