西灣筆記

擷英採華,以備不需!

【譯】如何撰寫Git提交訊息

• Git, Commit Message

這篇筆記、翻譯自博文:How to Write a Git Commit Message,作者Chris Beams。尊重他人勞動果實,轉載請註明!

2015-11-01-01.png

引言:為什麼好的提交訊息很重要

如果你隨意瀏覽一些Git存儲庫的日誌,你可能會發現提交訊息或多或少都亂成一團。例如,看看我早些時候向Spring提交的一些gems

$ 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提交訊息是和其他開發人員就一個改動的上下文進行溝通的最佳方式(實際上也是和未來的他們自己)。一個diff會告訴你作了哪些改動,但只有提交訊息能正確地告訴你為什麼。Peter Hutterer做了很好的詮釋:

重建一段程式碼的上下文是一種浪費。我們不能完全避免,所以我們應竭盡所能去減少它、越多越好。提交訊息完全可以做到這點,因此,提交訊息顯示了這個開發人員是否是一個好的協作者。

如果你還不曾考慮過如何更好地撰寫Git提交訊息的話,這可能是因為你沒有花多少時間使用git log和相關工具。這是一個惡性循環:因為提交歷史是結構混亂、前後矛盾的,人們不會在使用或打理它上花太多時間。而且,因為不被常用或打理,它將保持結構混亂、前後矛盾的。

但精心打理的日誌是優雅和有用的。 git blamerevertrebaselogshortlog等子指令都會復活。查看其他人的提交和拉取請求成為值得做的事,並可獨立完成。理解數月或數年前所發生的原委就變得不僅可能,而且高效。

一個專案的長期成功取決於(和其他方面相比)維護工作,而對於維護人員來說、鮮有比專案日誌功能更強大的工具。花時間去學習如何正確地打理是值得的。起初可能是個麻煩、不久變成習慣,最後成為所有參與者自豪感和生產力的來源。

在這篇文章中,我將探討保持一個健康的提交歷史的最基本的要點:如何撰寫個人提交訊息。其他重要實踐如壓縮提交則不會涉及。也許我會在隨後的文章裡進行探討。

大多數編程語言都有完善的構成慣用風格的慣例,例如,命名、格式等等。當然,這些慣例千差萬別;但大多數開發者都同意:選擇一種並堅持下去、遠比各行其是而混亂不堪強的多。

一個團隊訪問提交日誌的方式應當相同。為了創建有用的修訂版本歷史記錄,團隊應首先在提交訊息的慣例上達成一致,並至少確定以下三樣事情:

樣式。標記語法、自動換行間距、語法、大小寫、標點符號。把這些東西都寫出來,而不是靠臆測,並讓這一切盡可能的簡單。最終的結果將是一個非常一致的日誌,不僅讀來引人入勝,而且確實會定期進行審閱。

內容。哪些信息應當包含在提交訊息的正文(如果有的話)中?哪些不應包含?

元資料。應當如何引用議題跟踪ID、拉取請求編號等等?

幸運的是,如何生成規範的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(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 <[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個字符並不是硬性的限制,而只是經驗法則【Rule of thumb,拇指規則,又作:經驗法則】。保持主題行在這個長度內可確保其可讀性,並迫使作者花點時間考慮下以最簡潔的方式來闡述發生了什麼。

建議:如果你難於概述主題,那可能是你一次提交了太多的改動。爭取原子提交(一個提交一個議題)。

GitHub的使用者介面充分照顧了這些慣例。如果你超過了50個字符的限制,它會給予警告:

2015-11-01-02.png

而且、會以省略號截斷任何長度超過69個字符的主題行:

2015-11-01-03.png

所以爭取50個字符以內,但以69為硬性限制。

3.主題行首字母大寫

這正如聽起來那麼簡單。所有主題行起始於大寫字母。

例如:

而不是:

4.主題行結尾不要使用句號

主題行結尾處的標點符號是沒有必要的。再說,當你試圖將其保持在50個字符以內時,空間就很珍貴。

例如:

而不是:

5.在主題行使用祈使語氣

祈使語氣僅僅表示「如發號施令般發言或書寫」。舉幾個例子:

你現在讀到的七條規則的每一條都是以祈使語氣書寫(「正文在72個字符處換行」,等等)。

祈使語氣聽起來稍顯失禮;因而我們並不常用。但它卻很適合於Git提交的主題行。原因之一、Git本身在代替你創建提交時使用了祈使語氣。

例如,當使用git merge時默認創建的訊息讀起來就像這樣:

Merge branch 'myfeature'

而使用git revert時:

Revert "Add the thing with the stuff"

This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

或者點擊GitHub拉取請求上的「合併」按鈕時:

Merge pull request #123 from someuser/somebranch

所以,當你使用祈使語氣撰寫提交訊息時,你在遵循git本身內置的慣例。例如:

起初這麼撰寫可能有點彆扭。我們更習慣於以陳述語氣發言、如同報告事實一般。這就是為什麼提交訊息最終讀起來經常像這樣:

並且有時、提交訊息被撰寫成了內容的描述:

為了消除困惑,這裡有一條簡單的屢試不爽的規則。

格式正確的git提交的主題行應該總是能夠完成下面的句子:

例如:

請注意,這對於其他非祈使語氣的格式是行不通的:

謹記:使用祈使語氣很重要這一點、僅限於主題行。當你撰寫正文時,可以放寬這個限制。

6.正文在72個字符處換行

Git從不會自動換行。當你撰寫提交訊息正文時,你得留意右邊距,並手動換行。

推薦在72個字符處換行,這樣git在保持長度在80個字符以內的同時有足夠的空間來縮進文本。

這裡一個好的文本編輯器可以有所幫助。例如,當你撰寫git提交時,配置Vim在72個字符處換行是很容易的。不過,通常IDE們對於提交訊息的文本換行所提供的智能支持都很糟糕(儘管在最近的版本中,IntelliJ IDEA 終於 變得 好多 了)。

7.用正文來解釋是什麼以及為什麼,而不是怎麼樣

來自Bitcoin Core的提交是一個解釋改動內容和原因的很好的例子:

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.

看看完整的diff,並想想作者當時花時間去提供的這個上下文節約了同事和未來的提交者多少時間。如果他沒有這麼做,那麼它可能永遠丟失了。

在大多數情況下,你可以略去改動的具體細節。在這方面程式碼一般都是自解釋的(如果程式碼複雜到需要額外的解釋,那就是源碼註釋的工作了)。僅專注於把改動原因言明擺在首位——改動前它們如何工作(那樣有什麼問題),現在如何工作,以及為什麼你決定以這種方式解決問題。

在未來感謝你的維護者也許就是你自己!

建議

學著去熱愛命令列。把IDE丟在一邊吧。

明智的做法是去擁抱命令行,理由如git子指令那樣多。Git極其強大;IDE們同樣也是,但卻各不相同。我每天都在用IDE (IntelliJ IDEA)、其它用的也比較多 (Eclipse),但我從未見過有整合git的IDE能夠匹敵命令列的易用與強大(一旦你了解它)。

某些git相關的IDE功能是極好的,比如呼叫git rm刪除一個檔案,以及用git重命名檔案。當你開始嘗試通過IDE去提交、合併、重訂、或做複雜的歷史分析時,一切都將分崩離析。

當談到充分發揮git的強大功能時,那就非命令列莫屬了。

謹記,不管你用Bash或Z Shell,都有tab補齊腳本來減輕記住子指令和開關的痛苦。

閱讀Pro Git

Pro Git這本書是網上免費提供的,寫的也非常棒。好好使用吧!

comments powered by Disqus