為什麼好的 Commit Message 這麼重要?
每次看到亂七八糟的 git commit message,我都會覺得渾身不對勁。所謂的「亂七八糟」,我指的是這幾種情況:
- 格式毫無章法,東一筆西一筆
- 寫得太含糊,讓人看了也不知道改了什麼
- 組織混亂,難以理解
好的 commit message 應該要簡潔、有條理、格式一致。寫好它當然要花點心力,但有幾個理由值得我們這樣做:
- 就像程式碼一樣,commit message 寫一次但會被讀很多次。花時間寫好它是值得的。
- 如果容許爛 commit message 存在,等於在傳達一個訊息:你不在乎程式碼的可維護性。這對建立良好的工程文化很不利。
Chris Beams 寫的 How to Write a Git Commit Message 是我讀過關於這個主題最好的文章。Chris 很清楚地解釋了為什麼好的 commit message 很重要,以及該怎麼寫。你可以從這個範例看看好的 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 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
這個範本是基於著名的 Tim Pope’s Note About Git Commit Messages。
大家都怎麼寫 Commit Message?
我不打算重複別人已經說過的東西。我想做的是蒐集一些真實世界的範例,看看可以從中學到什麼。
Linux
Subsurface
Subsurface 是 Linus Torvalds 開發的專案,他當然也是 Git 的創造者。以下是 Subsurface 開發者使用的格式:
Header line: explain the commit in one line (use the imperative)
Body of commit message is a few lines of text, explaining things
in more detail, possibly giving some background about the issue
being fixed, etc etc.
The body of the commit message can be several paragraphs, and
please do proper word-wrap and keep columns shorter than about
74 characters or so. That way "git log" will show things
nicely even when it's indented.
Make sure you explain your solution and why you're doing what you're
doing, as opposed to describing what you're doing. Reviewers and your
future self can read the patch, but might not understand why a
particular solution was implemented.
Reported-by: whoever-reported-it
Signed-off-by: Your Name <[email protected]>
如果改動本身很簡單,好的 commit message 可以非常簡潔:
Set proper mode for file open dialog
Fixes #913
如果有需要,也可以寫得很詳細:
Planner: Count the minimum stop time towards o2time
When doing backgas breaks, count the minimum stop time towards o2time.
Previously, the initial minimum stop wasn't counted, so the time of the first
segment on oxygen was min_switch_duration + 12 minutes.
E.g. with 1 minute minimum switch duration.
Previously:
depth duration runtime gas
40m 1min 1min air
40m 34min 35min
21m 2min 37min
21m 1min 38min EAN50
18m 1min 39min
15m 3min 42min
12m 4min 46min
9m 5min 51min
6m 13min 64min oxygen <--13 minutes on O2
6m 6min 70min air
6m 2min 72min oxygen
0m 1min 73min
Now:
depth duration runtime gas
40m 1min 1min air
40m 34min 35min
21m 2min 37min
21m 1min 38min EAN50
18m 1min 39min
15m 3min 42min
12m 4min 46min
9m 5min 51min
6m 12min 63min oxygen
6m 6min 69min air
6m 2min 71min oxygen
0m 1min 72min
Signed-off-by: Rick Walsh <[email protected]>
Signed-off-by: Dirk Hohndel <[email protected]>
Go
貢獻指南中給出了以下範例:
math: improved Sin, Cos and Tan precision for very large arguments
The existing implementation has poor numerical properties for
large arguments, so use the McGillicutty algorithm to improve
accuracy above 1e10.
The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm
Fixes #159
我其實很喜歡 Go 開發者使用的簡潔風格:
fmt: don't unread eof scanning %x
When scanning a hex byte at EOF, the code was ungetting the eof,
which backed up the input and caused double-scanning of a byte.
Delete the call to UnreadRune.
This line appeared in 1.5 for some reason; it was not in 1.4 and
should be removed again for 1.5
Fixes #12090.
Change-Id: Iad1ce8e7db8ec26615c5271310f4b0228cca7d78
Reviewed-on: https://go-review.googlesource.com/13461
Reviewed-by: Andrew Gerrand <[email protected]>
這是另一個寫得很好的 commit message:
runtime: make sure heapBitsBulkBarrier cannot be preempted
Changes the torture test in #12068 from failing about 1/10 times
to not failing in almost 2,000 runs.
This was only happening in -race mode because functions are
bigger in -race mode, so a few of the helpers for heapBitsBulkBarrier
were not being inlined, and they were not marked nosplit,
so (only in -race mode) the write barrier was being preempted by GC,
causing missed pointer updates.
Filed issue #12069 for diagnosis of any other similar errors.
Fixes #12068.
Change-Id: Ic174d9b050ba278b18b08ab0d85a73c33bd5b175
Reviewed-on: https://go-review.googlesource.com/13364
Reviewed-by: Austin Clements <[email protected]>
LLVM
LLVM 開發者並不強制要求 commit message 的格式,但有提供一些指引。顯然他們沒有遵循 Git commit message 的風格,因為 LLVM 的主要版本庫還在用 Subversion。不過你還是可以在那裡找到很多寫得很好的 commit message。
x86: Emit LAHF/SAHF instead of PUSHF/POPF
NaCl's sandbox doesn't allow PUSHF/POPF out of security concerns (priviledged emulators have forgotten to mask system bits in the past, and EFLAGS's DF bit is a constant source of hilarity). Commit r220529 fixed PR20376 by saving cmpxchg's flags result using EFLAGS, this commit now generated LAHF/SAHF instead, for all of x86 (not just NaCl) because it leads to an overall performance gain over PUSHF/POPF.
As with the previous patch this code generation is pretty bad because it occurs very later, after register allocation, and in many cases it rematerializes flags which were already available (e.g. already in a register through SETE). Fortunately it's somewhat rare that this code needs to fire.
I did [[ https://github.com/jfbastien/benchmark-x86-flags | a bit of benchmarking ]], the results on an Intel Haswell E5-2690 CPU at 2.9GHz are:
| Time per call (ms) | Runtime (ms) | Benchmark |
| 0.000012514 | 6257 | sete.i386 |
| 0.000012810 | 6405 | sete.i386-fast |
| 0.000010456 | 5228 | sete.x86-64 |
| 0.000010496 | 5248 | sete.x86-64-fast |
| 0.000012906 | 6453 | lahf-sahf.i386 |
| 0.000013236 | 6618 | lahf-sahf.i386-fast |
| 0.000010580 | 5290 | lahf-sahf.x86-64 |
| 0.000010304 | 5152 | lahf-sahf.x86-64-fast |
| 0.000028056 | 14028 | pushf-popf.i386 |
| 0.000027160 | 13580 | pushf-popf.i386-fast |
| 0.000023810 | 11905 | pushf-popf.x86-64 |
| 0.000026468 | 13234 | pushf-popf.x86-64-fast |
Clearly `PUSHF`/`POPF` are suboptimal. It doesn't really seems to be worth teaching LLVM about individual flags, at least not for this purpose.
Reviewers: rnk, jvoung, t.p.northover
Subscribers: llvm-commits
Differential revision: http://reviews.llvm.org/D6629
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244503 91177308-0d34-0410-b5e6-96231b3b80d8
更多參考資料
以下是一些有提供 commit message 指引的專案列表: