Gitコミットメッセージの書き方
コミットメッセージは重要です。上手な書き方をご紹介します。
はじめに なぜ良いコミットメッセージが重要なのか
Git リポジトリのログを見てみると、コミットメッセージは多かれ少なかれ雑然としていることに気づくでしょう。例えば、私がSpringにコミットしたばかりの頃の珠玉のメッセージを見てみましょう。
code: bash
$ 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
code: bash
$ 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
あなたはどちらを読みたいですか?
前者は長さや形が様々で、後者は簡潔で一貫性があります。
前者はデフォルトで起こることで、後者は偶然に起こることはありません。
これらのリポジトリのコントリビューターは、よく練られた Git のコミットメッセージが、仲間の開発者(そして将来の自分)に変更の状況を伝えるための最良の方法であることを知っています。diff を見れば何が変わったのかはわかりますが、なぜ変わったのかをきちんと伝えることができるのはコミットメッセージだけです。Peter Hutterer氏はこの点 をよく指摘しています。 コードの一部の文脈を再構築することは無駄です。完全に回避することはできませんが、可能な限り削減するために努力すべきです。コミットメッセージはまさにそれを可能にするものであり、結果として、コミットメッセージは開発者が良い協力者であるかどうかを示すものとなります。
もしあなたがGitの優れたコミットメッセージとは何かについてあまり考えたことがないのなら、それはあなたが git log やその関連ツールをあまり使っていないからかもしれません。ここには悪循環があります。コミットの履歴が構造化されておらず一貫性がないため、それを利用したり管理したりすることにあまり時間をかけられないのです。そして、使われず、手入れもされないので、構造化されていない、一貫性のない状態が続くのです。
git blame、revert、rebase、log、shortlog、その他のサブコマンドに命が吹き込まれます。他の人のコミットやプルリクエストをレビューすることは、やる価値のあることであり、突然独立してできるようになります。何ヶ月も何年も前に起こったことの理由を理解することは、可能であるだけでなく、効率的です。
プロジェクトの長期的な成功は保守性にかかっており、メンテナはプロジェクトのログよりも強力なツールを持っていません。そのためには、時間をかけてログの管理方法を学ぶ必要があります。最初は面倒かもしれませんが、すぐに習慣化され、最終的には関係者全員の誇りと生産性の源となります。
この記事では、健全なコミット履歴を保つための最も基本的な要素である、個々のコミットメッセージの書き方について説明します。コミットメッセージの書き方です。次回以降の記事で紹介します。
ほとんどのプログラミング言語では、名前の付け方や書式など、慣用的なスタイルを構成するものとして、確立された慣習があります。もちろん、これらの慣例にはバリエーションがありますが、多くの開発者は、誰もが自分のことをやらずに混乱するよりも、一つを選んでそれを守る方がはるかに良いということに同意しています。
チームのコミットログへのアプローチも同様です。便利なリビジョン履歴を作成するために、チームはまず、少なくとも以下の3つを定義したコミットメッセージの規約に同意する必要があります。
スタイル: マークアップの構文、折り返しの余白、文法、大文字、句読点。これらを明確にし、推測を排除して、できるだけシンプルにします。最終的には、読むのが楽しいだけでなく、実際に定期的に読まれるような、驚くほど一貫性のあるログになります。
コンテンツ: コミットメッセージの本文には、どのような情報を含めるべきでしょうか?また、何を含めるべきではないのでしょうか。
メタデータ: issue tracking ID、pull request numberなどはどのように参照されるべきか?
幸いなことに、Git のコミットメッセージとして何がふさわしいかについては、確立された慣習があります。実際、それらの多くは、ある種のGitコマンドが機能する際に想定されています。新たに考案する必要はありません。以下の7つのルールに従うだけで、プロのようなコミットができるようになります。
優れたGitコミットメッセージの7つのルール
心に留めておいてください。これは以前から言われていることです。(参考資料:1〜6)
例えば、以下のようになります。
code: TEXT
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:
1. 件名と本文を空行で分ける
必須ではありませんが、コミットメッセージの最初に変更内容をまとめた短い行 (50 文字以下) を入れ、その後に空行を入れてからより詳細な説明を入れるとよいでしょう。コミットメッセージの最初の空行までのテキストはコミットタイトルとして扱われ、Git 全体でそのタイトルが使われます。たとえば、Git-format-patch(1)はコミットをメールに変換する際に、タイトルをSubject行に、コミットの残りの部分を本文に使用します。
まず、すべてのコミットで件名と本文の両方が必要なわけではありません。一行で済むこともあります。特に、変更内容が単純でそれ以上の説明が必要ない場合などです。例えば、以下のようになります。
code: TEXT
Fix typo in introduction to user guide
これ以上何も言う必要はありません。もし読者がこのタイプミスは何だったのだろうと思ったら、変更点そのものを見ればいいのです。つまり、git show や git diff、git log -p を使えばいいのです。
このようなことをコマンドラインでコミットする場合は、git commit の -m オプションを使うのが簡単です。
code: bash
$ git commit -m"Fix typo in introduction to user guide"
しかし、あるコミットが少しでも説明や文脈を必要とする場合は、本文(Body)を書く必要があります。例えば:
code: bash
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のこのセクションをお読みください。 いずれにしても、件名と本文を分離することは、ログを見るときに役に立ちます。これがログ・エントリの全文です。
code: bash
$ 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)
and turns it back into a chess game.
そして今度は git log --oneline で、件名だけを表示します。
code: bash
$ git log --oneline
42e769 Derezz the master control program
もしくは、git shortlog では、ユーザーごとにコミットをグループ化し、件名だけを表示して簡潔にまとめています。
code: bash
$ 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 の UI は、こうした規約を十分に理解しています。50 文字の制限を超えると警告が表示されます。
https://gyazo.com/1d3b5c4b61eb7e682f9c69be51c1082b
また、72文字以上の件名は、省略記号で切り捨てられます。
https://gyazo.com/c7d1bc066fb5f55a06ec14f0eb1324b3
そのため、50文字を目標としますが、72文字がハードリミットと考えてください。
3. 件名を大文字にする
これはとても簡単なことです。件名はすべて大文字で始めましょう。
例えば、次のようにします。
code: COMMIT MESSAGE
accelerate to 88 miles per hour
の代わりに
code: COMMIT MESSAGE
Accelerate to 88 miles per hour
4. 件名の最後にピリオドを入れない
件名の最後に句読点は不要です。また、50文字以内に収めるためには、スペースが貴重になります。
例:
code: COMMIT MESSAGE
Open the pod bay doors.
の代わりに
code: COMMIT MESSAGE
Open the pod bay doors
5. 件名には命令形を使う
命令形とは、「命令するように話す、書く」という意味です。いくつか例を挙げましょう。
Clean your room
Close the door
Take out the trash
今お読みいただいている7つのルールは、いずれも命令形で書かれています(「本文は72文字で折り返す」など)。
命令形はちょっと失礼な感じがするので、私たちはあまり使いません。しかし、Gitのコミットの件名には最適です。その理由のひとつは、Git 自身があなたに代わってコミットを作成するときにこの命令形を使うからです。
たとえば、git merge を使ったときのデフォルトのメッセージは次のようになります。
code: TEXT
Merge branch 'myfeature'
また、git revertを使用する場合は:
code: TEXT
Revert "Add the thing with the stuff"
This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.
あるいは、GitHubのプルリクエストで「Merge」ボタンをクリックした場合は:
code: TEXT
Merge pull request #123 from someuser/somebranch つまり、コミットメッセージをインペリアルで書くときには、Gitに組み込まれた規約に従うことになります。たとえば、次のようになります。
Refactor subsystem X for readability (サブシステム X を読みやすくリファクタリングする)
Update getting started documentation (スタートアップドキュメントの更新)
Remove deprecated methods (非推奨のメソッドの削除)
Release version 1.0.0 (バージョン 1.0.0 のリリース)
このような書き方は、最初は少し戸惑うかもしれません。私たちは、事実を報告するための指示ムードで話すことに慣れています。そのため、コミットメッセージはしばしば次のようになります。
Fixed bug with Y (Yのバグを修正)
Changing behavior of X (Xの動作の変更)
また、コミットメッセージがその内容の説明として書かれることもあります。
More fixes for broken stuff (壊れたものをさらに修正)
Sweet new API methods (新しいAPIメソッドの追加)
混乱を避けるために、ここでは常に正しい情報を得るためのシンプルなルールを紹介します。
適切に作成された 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 を使えば、Git のコミットを書くときにテキストを 72 文字で折り返すように設定するのは簡単です。しかし伝統的に、IDE はコミットメッセージでのテキストの折り返しをスマートにサポートするのが苦手でした (最近のバージョンでは IntelliJ IDEA がようやくこの点を改善してきましたが)。
7. 本文では、「何を」「なぜ」「どのように」を説明する
Bitcoin Coreのこのコミットは、何が変わったのか、なぜ変わったのかを説明する良い例です。
code: COMMIT MESSAGE
commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille <pieter.wuille@gmail.com>
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)し、他のIDEも広く使っています(Eclipse)が、GitのIDE統合がコマンドラインの使いやすさと力強さに匹敵するものは見たことがありません(一度知ってしまえば)。
たとえば、ファイルを削除したときに git rm を呼び出したり、ファイル名を変更したときに git で適切な処理をしたりといった、Git に関連する IDE の機能は非常に貴重なものです。しかし、すべてがうまくいかないのは、IDE を使ってコミットやマージ、リベース、高度な履歴分析などを行おうとするときです。
Git の力を最大限に発揮させるには、やはりコマンドラインに限ります。
Bash、Zsh、Powershellのどれを使うにしても、サブコマンドやスイッチを覚える手間を省いてくれるタブ補完スクリプトがあることを覚えておきましょう。
Pro Gitを読むこと
Pro Gitの本はオンライン (日本語版:)で無料で手に入りますが、これが素晴らしい。ぜひ活用してください。 参考資料