Gitコミットメッセージの書き方

Contents: はじめに|7つのルール|ヒント

はじめに。 Why good commit messages matter

任意の Git リポジトリのログをブラウズすると、おそらくそのコミットメッセージは多かれ少なかれ混乱していることに気づくことでしょう。 たとえば、私が Spring にコミットしはじめたころのこれらのメッセージを見てみましょう。 同じリポジトリからの最近のコミットと比較してみてください。

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"5ba3db6 Fix failing CompositePropertySourceTests84564a0 Rework @PropertySource early parsing logice142fd1 Add tests for ImportSelector meta-data887815f Update docbook dependency and generate epubac8326d Polish mockito usage

どちらを読みたいと思いますか。

前者は長さと形式がさまざまで、後者は簡潔で一貫しています。 Linux カーネルと Git 自体が素晴らしい例です。 Spring Boot や Tim Pope が管理するリポジトリを見てください。

これらのリポジトリの貢献者は、よく練られた Git commit メッセージが、仲間の開発者 (そして実際に将来の自分) に変更についてのコンテキストを伝える最善の方法であることを理解しています。 diff は何が変わったかを教えてくれますが、コミットメッセージだけがその理由を適切に伝えることができるのです。 Peter Hutterer はこの点をよく指摘しています。

コード片のコンテキストを再確立することは無駄です。 それを完全に避けることはできないので、私たちの努力はそれを可能な限り減らすことに向けられるべきでしょう。 コミットメッセージはまさにそれを行うことができ、結果として、コミットメッセージは開発者が良い協力者であるかどうかを示します。

何が優れた Git コミットメッセージを作るかについてあまり考えたことがない場合、それは git log や関連ツールを使ってあまり時間をかけていない可能性があります。 ここには悪循環があります。コミット履歴が構造化されておらず一貫性がないため、それを使用したり世話をしたりすることにあまり時間を費やさないのです。 そして、コミット履歴は使用されず、ケアされないので、構造化されておらず、一貫性がありません。

しかし、よくケアされたログは美しく、有用なものなのです。 git blame, revert, rebase, log, shortlog といったサブコマンドが生きてきます。 他の人のコミットやプルリクエストをレビューすることは、やる価値のあることになり、突然独立して行うことができるようになります。

プロジェクトの長期的な成功は、その保守性にかかっており、保守者は自分のプロジェクトのログより強力なツールをほとんど持っていません。 ログを適切に管理する方法を学ぶために時間をかける価値があります。 最初は面倒かもしれませんが、すぐに習慣となり、最終的には関係者全員の誇りと生産性の源となります。

この投稿では、健全なコミット履歴を保つための最も基本的な要素、すなわち個々のコミットメッセージの書き方だけを扱います。 コミットスクワッシング (commit squashing) のような他の重要なプラクティスもありますが、ここでは触れません。

ほとんどのプログラミング言語には、慣用的なスタイル、すなわち、名前付け、フォーマット、などを構成するものとして、確立された慣習があります。 もちろん、これらの慣習にはバリエーションがありますが、ほとんどの開発者は、1 つを選んでそれに固執することが、誰もが自分自身のことをするときに起こる混乱よりもはるかに良いということに同意します。 有用な改訂履歴を作成するために、チームはまず、少なくとも次の 3 つの事柄を定義するコミット メッセージの規約に同意する必要があります。 マークアップ構文、折り返し余白、文法、大文字、句読点。 これらのことを明確にし、当て推量を排除し、可能な限りすべてをシンプルにします。 最終結果は、読むのが楽しいだけでなく、実際に定期的に読まれる、非常に一貫したログになります。 コミットメッセージの本文はどのような情報を含むべきでしょうか (もしあれば)。 何を含むべきではないですか。

メタデータ。 課題追跡 ID、プルリクエスト番号などをどのように参照すべきか。

幸いなことに、何が慣用的な Git コミットメッセージになるかについては、確立された慣例があります。 実際、それらの多くは、ある Git コマンドが機能する方法で仮定されています。 あなたが再発明しなければならないことは何もありません。 以下の7つのルールに従うだけで、プロのようにコミットできるようになります。

優れたGitコミットメッセージの7つのルール

Keep in mind: これはすべて以前から言われていることです。

  1. 件名と本文を空白行で分ける
  2. 件名は50文字まで
  3. 件名は大文字で
  4. 件名をピリオドで終わらせない
  5. 件名は命令形を使う
  6. 本文は72字で折り返す
  7. 本文を、何を、なぜ対訳するのに使う
  8. 本文は、なぜ、なぜ、なぜ、何を対訳するのに使う
  9. 本文は、なぜ、なぜ、何を対訳するのに使う
  10. 本文は、なぜ、なぜ、何を対訳するのに使う

例:

Summarize changes in around 50 characters or lessMore detailed explanatory text, if necessary. Wrap it to about 72characters or so. In some contexts, the first line is treated as thesubject of the commit and the rest of the text as the body. Theblank line separating the summary from the body is critical (unlessyou 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 youare making this change as opposed to how (the code explains that).Are there side effects or other unintuitive consequences of thischange? 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 hereIf you use an issue tracker, put references to them at the bottom,like this:Resolves: #123See also: #456, #789

件名と本文を空行で分ける

git commitマニュアルページより:

必須ではありませんが、変更の要約を短い (50 文字以下) 行でコミットメッセージを始め、その後空行、さらに詳しい説明とするとよいでしょう。 コミットメッセージの最初の空行までのテキストはコミットタイトルとして扱われ、そのタイトルはGit全体で使用されます。 例えば Git-format-patch(1) はコミットをメールに変換し、件名にタイトルを、本文にコミットの残りを使用します。

第一に、すべてのコミットが件名と本文の両方を必要とするわけではないということです。 特に変更が非常に単純で、それ以上の文脈が必要ない場合、一行で十分なこともあります。 例えば、

Fix typo in introduction to user guide

これ以上何も言う必要はありません。もし読者がこのタイプミスは何だろうと思ったら、git showgit diffgit log -p を使って変更点そのものを見てみればいいだけです。

このようにコマンドラインでコミットする場合、git commit:

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

-mオプションを使うのは簡単ですが、コミットにちょっとした説明や文脈が必要な場合、本文を記述する必要があります。 例えば:

Derezz the master control programMCP 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 logcommit 42e769bdf4894310333942ffc5a15151222a87beAuthor: 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 --oneline42e769 Derezz the master control program

あるいは、ユーザーごとにコミットをグループ化した git shortlog でも件名だけを表示して簡潔にしています。

件名を50文字に制限する

50文字というのは難しい制限ではなく、単なる経験則に過ぎません。 件名をこの長さに保つことで、読みやすくなり、著者は何が起こっているかを説明する最も簡潔な方法について少し考えざるを得なくなります。

Tip: 要約するのに苦労している場合、一度に多くの変更をコミットしすぎている可能性があります。 アトミック コミットに努めましょう (別の投稿で取り上げます)。

GitHub の UI はこれらの慣習を完全に理解しています。 50 文字の制限を超えると警告されます。

また、72 文字以上の件名は省略記号で切り捨てられます。

だから、50 文字に達するようにするが、72 文字を厳しい制限と考える。

たとえば、

  • Accelerate to 88 miles per hour

Instead of:

  • accelerate to 88 miles per hour

件名の最後にピリオドは使わない

宛名には、句読点をつける必要はないでしょう。 また、50文字以内に収めようとすると、スペースは貴重です。

例:

  • Open the pod bay doors

代わりに、

  • Open the pod bay doors.を使用します。

件名に命令形を使う

Imperative moodは「命令や指示を与えるように話されたり書かれたりする」という意味にすぎません。 いくつかの例を挙げてみましょう。

  • 部屋を掃除する
  • ドアを閉める
  • ゴミを出す

今読んでいる7つのルールはそれぞれ命令形で書かれています(「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 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 your subject line here

たとえば。

  • もし適用されたら、このコミットはサブシステム X を読みやすくリファクタリングします
  • もし適用されたら、このコミットは getting started documentation を更新します
  • もし適用されたら、このコミットは非推奨メソッドを取り除きます
  • もし適用されたら、このコミットはバージョン 1.X をリリースします
      もし適用されたら、このコミットでサブシステムをリファレンスにします0.0
  • If applied, this commit will merge pull request #123 from user/branch

Notice how this doesn’t work for the other non-imperative form:

  • このコミットが適用されると、Y のバグが修正されます
  • このコミットが適用されると、X の挙動が変わります
  • このコミットが適用されると、壊れたものの修正がさらに行われます
  • 適用されると、新しい API メソッドを甘くします

Remember: 命令文の使用は件名においてのみ重要です。

本文を 72 文字で折り返す

Git はテキストを自動的に折り返すことはありません。

推奨は 72 文字でこれを行うことで、Git がテキストをインデントするための十分なスペースを持ちつつ、すべてを全体で 80 文字以下に保つことができます。 例えば Vim では、Git のコミットを書くときにテキストを 72 文字で折り返すように設定するのは簡単です。 しかし、伝統的に、IDE はコミットメッセージのテキストラッピングのスマートなサポートを提供するのが苦手でした (最近のバージョンでは、IntelliJ IDEA がようやくこの点を改善しましたが)。

Use the body to explain what and why vs. (本文を使用して、何を、なぜ、どのように)

Bitcoin Core からのこのコミットは、何がなぜ変わったのかを説明する素晴らしい例です。

完全な diff を見て、著者が今ここでこのコンテキストを提供する時間を取ることによって、仲間や将来のコミッターの時間をどれだけ節約しているか考えてみてください。 もしそうしなければ、おそらく永遠に失われてしまうでしょう。

ほとんどの場合、変更がどのようになされたかについての詳細を省くことができます。 この点については、コードは一般的に自明です (そして、もしコードが非常に複雑で、散文で説明する必要がある場合は、ソース コメントがそのためにあります)。 変更前の動作 (そして、それの何が問題だったのか)、現在の動作、そして、なぜその方法で解決することにしたのか。

あなたに感謝する未来のメンテナは、あなた自身かもしれません!

Tips

コマンドラインを愛することを学ぶこと。 IDE を置き去りにする。

Gitのサブコマンドがあるのと同じくらい多くの理由から、コマンドラインを受け入れるのは賢明なことです。 Git は非常に強力です。IDE も同様ですが、それぞれ異なる方法で使用します。 私は毎日 IDE (IntelliJ IDEA) を使っていますし、他のもの (Eclipse) も広範囲に使っていますが、コマンド ラインの簡単さとパワーに匹敵するような Git の IDE 統合は見たことがありません (いったんそれを知ってしまえば)。

特定の Git 関連の IDE 機能は、ファイルを削除すると git rm を呼び出し、名前を変更すると git で正しいことを行うといった、非常に貴重なものです。 IDE を通してコミット、マージ、リベース、あるいは洗練された履歴解析を行おうとすると、すべてが崩れてしまいます。

Gitのフルパワーを行使するとなると、それはコマンドライン一辺倒になります。

Bash や Zsh、Powershell を使うにせよ、タブ補完スクリプトがあるので、サブコマンドやスイッチを覚える苦痛から解放されることを覚えておいてください。 活用しましょう!

header image credit: xkcd

コメントを残す

メールアドレスが公開されることはありません。