わかりやすいコミットメッセージの書き方 - 2013-04-24 - ククログ

ククログ

株式会社クリアコード > ククログ > わかりやすいコミットメッセージの書き方

わかりやすいコミットメッセージの書き方

もう1年以上前になりますが、コミットメッセージの書き方を説明しました。ざっくりまとめると、以下のことを説明しています。

  • わかりやすいコミットメッセージがいかに大切か
  • どのようなコミットメッセージがわかりやすいか(具体例付き)

この説明をしてからも、日々コミットしていくなかで新たに得られた「どうすればもっとわかりやすいコミットメッセージになるか」という知見が増えていました。これは、コミットへのコメントサービスの提供を開始した1ことも影響しています。このサービスでは、コミットへコメントするときに「どうして自分は他の書き方よりもこの書き方をわかりやすいと感じるか」を説明しています。その過程で「なんとなくこっちの方がよさそう」だったものを「具体的にこういうときにこう感じるのでこっちの方がよさそう」と何かしら理由を考えるようになりました。これにより、今までそれぞれの開発者でなんとなくだった考えが共有でき、チーム全体として「では○○という理由があるからこっちの書き方にしよう」と、考えを共有した上で自分達のスタイルを作っていくことができるようになりました。

今回はそんな日々の開発の中で明文化されたわかりやすいコミットメッセージの書き方を紹介します。理由もつけて紹介するので、自分達のチームに取り入れるときは、自分達にとっても本当にわかりやすいかどうかを検討してから判断してください。

付加情報を書く

コミットメッセージをわかりやすくするための1つの方法として、「○○しました」だけではなく、どうして○○をしたのかなどの情報を入れるという方法があります。しかし、なんでもいれればよいというものではありません。長すぎるコミットメッセージは読む気が失せてしまうからです。それではどのような情報は入れた方がよいのでしょうか。

revertした理由を書く

git revertをすると自動で「このコミットをrevertします」というログが入ります。この状態でコミットしている人は結構多いのではないでしょうか。

それでは、このrevertコミットを読む人のことを考えてみましょう。「どうしてこのコミットがrevertされたのか」ということが気になるはずです。revertしたときはrevertした理由を付加情報として書きましょう。

例えば、以下のrevertコミットは必要なファイルを追加し忘れたのでコミットしなおすためにrevertしています。

commit a0b6d964ef41f85bb825928813a67533da3d4663
Author: Kouhei Sutou <kou@clear-code.com>
Date:   Tue Mar 19 19:05:18 2013 +0900

    Revert "doc: update for renaming --query_expansion to --query_expander"

    This reverts commit 4837201f9fd01826c4dd21ced2b3f357a9e9bfcd.

    I forgot to add renamed files. Sorry...

実行したコマンドを書く

定形処理は自動化して誰でも簡単に間違いなく実行できるようにしていますよね。そのような自動化された処理を実行して一括で変更した内容をコミットする場合は、実行したコマンドを付加情報として書きます。

以下は、バージョン番号を更新したコマンドを付加情報として書いている例です。

commit 6a27a9f890453bf4f08c972ee53b2a40ba066489
Author: HAYASHI Kentaro <hayashi@clear-code.com>
Date:   Tue Apr 23 11:48:41 2013 +0900

    Bump up version number to 3.03

    make update-version NEW_VERSION_MAJOR=3 NEW_VERSION_MINOR=0 NEW_VERSION_MICRO=3

コマンドを書いておけば、他の人が同じことをやろうとしたときにヒントになるため、役立ちます。

英語だけで表現することにこだわらない

以前の記事では「コミットメッセージは英語で書きましょう」と説明していました。しかし、英語で表現することにこだわりすぎるのも考えものです。以前の記事で英語で書こうと説明していた理由は、多くの人が読めるからです。つまり、多くの人にわかりやすく伝えるために英語という手段を使いましょうということでした。もし、英語よりも多くの人にわかりやすく伝えられるのであれば、英語にこだわらずにその表現を使いましょう。

「どう変わったか」を伝える場合

「どう変わったか」を伝える場合は比較対象を縦に並べます。

例えば、CommitCommentTools::CommitsAnalyzerクラスのanalyzeメソッドをparetoメソッドにリネームしたとします。この場合は英語にすると以下のようになります。

Rename analyze method to pareto method of CommitCommentTools::CommitsAnalyzer class

この中で大事なことは「analyze」と「pareto」の対比です。英語で表現すると、読むとわかりますが、パッとみただけでは、そこまで目立ちません。では、どのように表現すればよいでしょうか。

テスティングフレームワークを使って開発をしたことがある人はassert_equalassertEqualsshould ==などが失敗したときにどのように表示されるかを思い出してください。以下のように期待値と実際の値を並べて表示しますよね。

expected: <analyze>
 but was: <pareto>

何かを比較するときは横ではなく縦に並べた方が違いがパッとみてわかりやすいのでこうなっています。例えば、「1文字目から違う」ということもわかりますし、「そもそも文字の長さが違う」ということもパッとみてわかります。

これをコミットメッセージに応用するとこうなります。

Rename method of CommitCommentTools::CommitsAnalyzer class

analyze ->
pareto

「どう変わったか」が大事なコミットメッセージを書くときは比較対象を縦に並べましょう。比較しているものが明確になりますし、違いもわかりやすくなります。

「少しだけ変わったこと」を伝える場合

縦に並べればなんでも違いがわかりやすくなるわけではありません。例えば、typoの修正は縦に並べても見つけることは大変です。

そんなとき、ひと手間かけるとグッとわかりやすくなります。

commit 27df8ff1fd26187bbc8e2817b633c31932559f18
Author: Haruka Yoshihara <yoshihara@clear-code.com>
Date:   Thu Apr 4 11:02:17 2013 +0900

    test: fix a typo

    TestDefaultPathRuels ->
    TestDefaultPathRules
                     ^^

違っている箇所の下に「^」で印をつけます。これがあれば、読む人はここに注目すればよいということが一目瞭然なのでわかりやすくなります。直した人はどこが違っていたかをすでに知っているためできるテクニックです。

なお、違っている桁の下に「^」をつけるのはPythonのdifflibで使われているスタイルです。

「使い方が変わったこと」を伝える場合

リファクタリングなどでより便利な書き方をできるようにすることはよくあることです。それを伝えたい場合も必ずしも英語にこだわる必要はありません。

例えば、以下のようにGroonga::Contextnewして自分でcloseしていたものを、ブロック内で実際の処理を行い、ブロックを抜けたら自動でcloseするようにしたとします。

diff --git a/lib/fluent/plugin/out_droonga.rb b/lib/fluent/plugin/out_droonga.rb
index 1baea60..6979c43 100644
--- a/lib/fluent/plugin/out_droonga.rb
+++ b/lib/fluent/plugin/out_droonga.rb
@@ -83,21 +83,30 @@ module Fluent
     def ensure_database
       return if File.exist?(@database)
       FileUtils.mkdir_p(File.dirname(@database))
-      context = Groonga::Context.new
+      create_context do |context|
       context.create_database(@database) do
       end
-      context.close
+      end
     end

     def ensure_queue
-      context = Groonga::Context.new
+      create_context do |context|
       context.open_database(@database) do
         Groonga::Schema.define(:context => context) do |schema|
           schema.create_table(@queue_name, :type => :array) do
           end
         end
       end
-      context.close
+      end
+    end
+
+    def create_context
+      context = Groonga::Context.new
+      begin
+        yield(context)
+      ensure
+        context.close
+      end
     end

     def load_handlers

この場合は、今、日本語で説明したことを英語で説明するのではなく、実際にどのように使い方が変わったかをコードで表現しましょう。コミットメッセージを読む人の多くは開発者です。開発者の多くは英語だけではなく、もちろん、コードのこともわかっているはずです。コードのことはコードで伝えましょう。その方が間違いなく伝わります。

commit badf11498eb38beaa6b104e0f51fb3eb3b27a331
Author: Kouhei Sutou <kou@clear-code.com>
Date:   Thu Apr 4 14:54:04 2013 +0900

    Extract common create and close context code

    Before:

        context = Context.new
        ...
        context.close

    After:

        create_context do |context|
          ...
        end

コミットメッセージを書く上で大事なことは、英語で書くことではなく「多くの人にわかりやすく情報を伝えること」です。そのために英語で書くという手段を使っているのです。英語で書くことだけにこだわらず、本来目指していた「多くの人にわかりやすく情報を伝えること」を実現するにはどうしたらよいかを考えてみてください。

英語で書く

英語以外で表現した方がわかりやすいケースを紹介しましたが、英語の方がわかりやすいケースもあります。どのような表現がよいか「わかりやすさ」という観点で考えてみてください。

文字列リテラルのクォートをダブルクォートに変更した場合

文字列リテラルに「'」(シングルクォート)あるいは「"」(ダブルクォート)のどちらも使えるプログラミング言語がいくつもあります。例えば、Rubyやシェルもそのような言語です。

同じソース内では表記を統一していた方が見通しがよくなります。そのため、「"」(ダブルクォート)に統一したとします。そのとき考えられるコミットメッセージには以下のようなものがあります。

Use "XXX" style string literal
Use " for string literal
Use '"' for string literal

最初のケースでは「"XXX"」で文字列リテラル一般を表現しようとしています。つまり、コードで表現してわかりやすくしようとしています。コードと同じ表記なのでわかりやすくなる人がいる一方で、「XXX」を強調している英語での書き方と見えてしまう人もいるため、かえってわかりにくくなる危険があります。

2つめは「"」そのものを書いています。ソース中では「double quote」と書くよりも「"」と書いていることの方が多いため、ソース中でよく見る字面にあわせてわかりやすくしようとしています。これもコードと同じ表記なのでわかりやすくなる人がいる一方で、「"」を英語での文脈で解釈してしまうと閉じる「"」を探してしまうことになり、かえってわかりにくくなる危険があります。

3つめは「"」だけだとわかりにくいため、「'"'」と「"」を強調しています。ただ、「'"'」と「"'"」で区別がつきにくいので「"」のことなのか「'」のことなのかがかえってわかりにくくなる危険があります。

このように違う意味で解釈される危険性を回避するために、英語表記も併記します。

commit 904e124f3459df3ee9138de5fef65450613c4058
Author: Kouhei Sutou <kou@clear-code.com>
Date:   Sun Apr 14 11:02:17 2013 +0900

    Use " (double quote) for string literal

こうすれば、「"」をプログラムの文脈で読んでパッとみて理解できるケースと、「"」が何のことかわからなかったケースもどちらにも対応できます。

ダブルクォートで囲んだ場合

シェルでは文字列をクォートで囲む必要はありません。しかし、文字列内に空白が入るかもしれないケースを考慮するとクォートで囲んでおいた方が無難です。

そんなときのコミットメッセージとしてコード片を使うことを考えると、例えば以下のようになります。

Add missing "..."

この書き方では、「"..."」という文字列リテラルになっていなかったのでそうしたというのを表現しようとしています。しかし、「...」が抜けていたので追加した、というようにも読めてしまいます。

この場合はクォートしたと英語で書いた方が伝わるでしょう。

Quote string expression

まとめ

コミットへのコメントサービスや日々の開発の中で試行錯誤してわかってきた、わかりやすいコミットメッセージの書き方を例と理由をあわせて紹介しました。理由もつけてあるので、自分達のチームに取り入れるかどうかは理由を検討した上で判断してください。

  1. 現在、1社に提供しており、近いうちに導入事例を紹介できる見込みです。