はじめに
自分がコミットメッセージを書くときに考えていることを書きます。
ただし、絶対にこの書き方をずっと続けるというわけでありません。日が経つにつれ、「そういえばこんなことも思ってた」「こういうのいいなあ」「これないわー」といった心境の変化があると予想するので、その時その時で手を入れていくつもりでいます(入れないかもしれません)。なので生煮えです。たぶんずっと生煮えです。それにかこつけて文章の文体もざっくりしています。
あと、あくまでもオレオレなので他の人の書き方をどうこうする意図はありません。うっかり参考になったらいいなあぐらいです。
最初に概念的な話をしてから後半で実際の書き方に入ります。
なお、全体的に git
を使う想定で書いていますが、それ以外でも大体同じだと思います。
コミットメッセージには何を書くのか
そのコミットでリポジトリに入れた差分が何をしているのか、なぜそうしているのかの要約を書きます。
diffにより何が変わったかを端的に伝えるのが目的です。端的といっても情報が足りないと読んだ側が困るので、diffを読む前に最低限知っておいてほしいことを不足なく書くイメージです。メールや記事などタイトルと本文が別にある文章のときに、文章で何を伝えようとしているのかをタイトルで表す感覚が、個人的には一番近いです。
なぜコミットメッセージを要約にするのか
そのコミットで何をしたか、なぜそうしたのかが他人にわかってほしいからです。他人というのは一緒に開発している人や、未来の(今何してるか忘れてしまった)自分でもあります。
なぜわかってほしいかというと、「そのコミットで何がどういう理由で変更されたか」という情報が後から重要になるからです。特に「なぜそうしたのか」の情報は特に必要です。例えば今の実装を修正したい時、ただ変更されたコミットだけがあるだけでは、今の実装がどうしてそうなっているのかは伝わりません。PRベースでの開発ならPRに書いてあればよいですが、そうでもない場合はお手上げになってしまいます。(特にそのコミットをした人がもう近くにいない、あるいは忘れてしまっている場合)理由がわかればその実装を本当に修正していいのか、その理由で実装した根拠は今も変わってないから変えちゃいけないのか、などの判断ができて先に進めます。割と書き忘れがちで、同時に記憶から抜けがちでもあります(少なくとも私は)
あと(あんまり当てはまる人いない気がしますが)個人的には、ライブラリなどをリリースするときのNEWS(Changelog)の材料代わりにもします。個人開発だとよほど大きい変更じゃないとmasterに直pushするため、コミットメッセージの情報がより重要です。前バージョンから何が変わったのか正確には覚えていられないので、コミットログを見て何が変わったのかを抜き出していくので、どんな機能がどう追加されたか、などはコミットメッセージで書いておくと便利なのでした。
いつコミットするの
場合によりけりですが、「1つの作業が終わったとき」です。1つの単位は自分次第なところが大きいですが、「なるべく小さく、かつ意味のある単位」だと思っています。
大体はある機能を実装したときにコミットするのが多いのですが、それも小さく分解して「この部分は既存コードのリファクタだから先にコミットしよう」「この部分は機能追加と一緒にコミットしないとなんで変えたかわからないから一緒にコミットしよう」などと考えてからコミットすることが多いです。まとめて変更してしまった場合は git add -p
で分割してコミットします。
例えば、ある大きい機能のうち一部だけ作った場合も、「限定的な状況では正しく動く」状態に持っていったらコミットします。例えば複数入力可能なフォームを作るとき、まずひとつだけ入力できるようにしたらコミットする、みたいな感じです。もちろん、「ぜんぜん動かないけどコミットしちゃおう」はないです。動作するけど限定的、というのが条件だと思っています。
なお、このように「全体の途中だけどコミットする」場合は、途中であることがわかるようにコミットメッセージを書きます。これについては後述します。
コミットを1つの作業ごとに分割する理由としては、コミット単位でさかのぼった時に細かい単位にしたいというのがあります。PRベースで開発しているとあんまりないのですが、個人の開発とかPRを使わないで開発している時、もしくはバグ調査で git bisect
なんかを使ってコミットごとに調査している場合、コミットのでの変更単位が大きいと作業しにくいです。1コミット戻ったらごっそりコードが巻き戻ると、そのコミットでエンバグしていたときに「どの部分でバグったんだ?」というのを更に調べる必要がありますが、コミットの変更量が少なければ(例外はあると思いますが)すぐにバグの原因を判断しやすくなります。
フォーマット編
ここから実際の書き方です。あくまで私の書き方なので参考程度にお考えください。
1行目
英語で、「このコミットでは何をした」というのを1文で書きます。日本語だと曖昧でもそれっぽく書けてしまうので、後から見たらよくわからないということが起きやすいイメージがあるので、なるべく英語で書いています。ただし、英語だと著しく効率が落ちる、周りが日本語話者のため後から見るときに日本語のほうが効率がいい、などがある場合は日本語で書きます。
あと英語で書く理由としては、もしコミットメッセージが英語で書きにくいのなら、「色々変更しすぎていてまとめきれない」ということだろうと考えています。これについては後述します。
その他気をつけるポイントは次のとおりです。
- 頭文字は大文字で動詞の現在形で書き始める(この辺は人によって好みがありそう)
- 最大80文字で収めたいですが、場合によりけり
- 固有名詞が入るとつらいときがありますが、そんな長い固有名詞使うなってことなのかもしれない(けどどうしようもないこともままある)
- 便利なときは冒頭にカテゴリをつける
- e.g)
test: fix a typo
- ライブラリのNEWS書くときに便利です(
test
で始まってたら実装変わってないはずだから見ないでいける)
- e.g)
- Redmineと連携してたりGitHubのissueを使ってたら番号も書く
- e.g.)
refs #1234 Implement Entry#summary
- 3行目のときもある
- e.g.)
- 作業途中でコミットする場合は後述
- 差分を作るために実行したコマンド(
$ rails new
など)- オプションをつけた場合はそのオプション込みで書いておくと、後からオプションによる生成物がどれか判定しやすくて差分の理由がわかるので全部書く
英語で書きにくいと感じる時
(個人の主観なので、人により感じ方は変わるはずです。あくまで私の場合は、ということで参考程度にお考えください)
(そもそも英語に慣れてなくて書きにくいという点は一旦除きます)
例えばどうしても1つの動詞だけで説明できなくて、 Do hoge & Do fuga
みたいにコミットメッセージを書いたとします。その場合、おそらく Do hoge
と Do fuga
の2つのコミットに分けられるな、とすぐ判断できます。これが日本語だと hogeとfugaをした
みたいにするっと書けてしまってあんまり違和感を感じないのでした。そのため、コミットの分割したほうがよさそうか? の判定のために英語で書きたいというのがあります。
なお、実装と一緒にテストをコミットする時、コミットメッセージにはテストを追加したことは大体書きません(なので、Implement hoge & add tests
みたいにはなりません)状況によってはテストと実装を分けてコミットすることがありますが、基本的には実装とテストは一緒にコミットしたい方です。(最近実装を先にやってテストが後追いになることが多いので、気をつけようと思いました)
2行目
空行にします。
3行目以降
補足説明を書きます。1行目で書ききれなかったが、あったほうが間違いなくdiffの中身が理解しやすくなる情報が補足情報です。
- e.g.) バグを直したとき
- 1行目でこういうバグ直したって言ったけどこれは実際にはこういうことが起きるバグ
- こうやると再現する
- こうなるのが自然だからそんなふうに直した
- e.g.) ベンチマークとったらその結果(ベンチマーク自体はリポジトリに入れるのがよさそう)
- e.g.) 単語をtypoしていたがその変更箇所がわかりにくい時(例えば以下のような感じです)
Fix a typo
poistion ->
position
^^
単語編
使わない単語
情報があまり含まれないから、という理由です。
- Change/Modify
- コミットしたから何かしら変えてるはず→情報が少ない
- →具体的に何をどうしてどう変えたのかを書く
時と場合により
- Update/Revise
- 大体のコミットは何かしら修正・更新してる→情報が少ない
-
Update XXX to do…
ならDo … for XXX
みたいにDoを主役にした文章にする(英語は大体最初に言うことがいちばん大事なので)- そのコミットで大事なのはUpdate/ReviseしたことよりもDoの内容
- ドキュメントの文章を綺麗にしたときは使うかも(句読点の位置替えたとか単語の位置調整したとか)
- ドキュメントに具体的に項目を追加した場合はその内容を書く(
doc: add ほげほげ
)
- ドキュメントに具体的に項目を追加した場合はその内容を書く(
- Fix/Add
- 何をどう直した
- よい:
Fix the bug that HogeUrlHelper generates incorrect URL
- よろしくない:
Fix HogeUrlHelper
-
HogeUrlHelper
の何を直したのかが伝わってこない
-
- Refactor
- 動詞としてよりカテゴリとして使うほうが良さそう
- あえて書かないといけないタイミングがわからない(大事なのはリファクタしたという事実より何をどうリファクタしたのかなのでそちらを書いたほうがよい)
よく使う単語・表現
動詞
- Implement(実装)
- Add(追加)
- Remove(削除)
- Extract(メソッドなどの切り出し)
- Integrate(統合・切り出していたメソッドを呼び出し元に展開して元メソッド削除)
- Use
- 大体なにかの代わりにこれ使うようにしたよ系
Use Symbol instead of String for URL option keys
形容詞関係
- いらないもの関連
- deprecated(非推奨)
- duplicated(重複)
- needless(不要・前まで使ってたけど要らなくなったメソッドとか)
- unused(実は使ってなかった・needlessと適当に使い分け)
- 入れ忘れたもの
- missing
- よりよいもの
- more proper/readable/meaningful
その他
- instead of
- XXXの代わりにYYYを使った、など
- trailing space(文末のスペース)
- blank line(空行)
- Remove needless blank lines
言語特有
- Rubyのインスタンスメソッドの頭に
#
Implement UsersController#index
- Rubyのクラスメソッドの頭に
.
Use .find_notes_metadatas instead of deprecated .find_notes
- rspecの
describe
の説明でも使います
特殊な場合
全体の途中だけどコミットする場合
文頭or文末に [WIP]
をつけてから1行目を普通に書き、WIPな状況を3行目以降に書く
WIPな状況として書くこと
- ここまでやった
- あとこれが残ってる
- これからこういうことをしたい(リファクタしたいとか)
e.g.) Add the tests for User#summary [WIP]
I added the test for User having both last_name and first_name.
TODO: Add tests for last_name or first_name only
おわりに
気持ち的にはこれぐらいできたらいいなと思っていますが、場合によってはもっとゆるくやってたりします。あくまでも指針の一つとして考えていけたら(もちろんできることに越したことはない)ぐらいの気持ちでいます。