はじめに
本内容は、ほぼこちらの記事の引用+翻訳です、俺は原文で読むよ、という方はこちらへどうぞ
Write Better Commits, Build Better Projects [1]
High-quality Git commits are the key to a maintainable and collaborative open- or closed-source project. Learn strategies to improve and use commits to streamline your development process.
GitHub’s top 10 blog posts of 2022 [2] にも選ばれており、人気のあった記事であることも伺えます。
本記事はこちらの@itoshoさんのGitのコミットメッセージの書き方(2023年ver.)にインスパイアされて書きました。こちらも併せてどうぞ。
なぜきれいなコミット履歴が必要なのか
中長期に渡りコードベースを維持・改善していくために、人が入れ替わっても「なぜこうなっているのか(いないのか)」を継承していく必要があるのは良く理解できると思います。この知識が失われている場合には、みな考古学者のように遺物から歴史を紐解いて行く必要があります。
これに対し、ADRなどのドキュメンテーションの必要性についてはしばしば語られますが、コミットログもまたコンテキストを残す手段として有用です。(ここでは触れませんが、Ticket、Issue、PRなども同様。)
このことについて [1] には以下のように記載されています。
コミットは、各コードがどのように、そしてなぜ生まれたかを直接的に記録する歴史的な記録です。さらに、人間が読むことのできるメッセージまでついてきます。その結果、リポジトリのコミット履歴は、開発者がコードを説明し理解するための最高のツールになります。
この歴史的な記録をきちんと整備することが、後世の人間が歴史を正しく辿れるようになる道筋です。
そのための方法を以降に記載します。
よりよいコミットの書き方
まず初めに、あなたの作るコミットはコミュニケーションツールである、という意識を持ちましょう。
あなたのコミットをみた誰か、あるいは後日のあなた自身がより簡単かつ正確に変更が理解できることが重要です。
そのための重要な要素が以下の3点です。
- コミットをストーリー仕立てにする
- 各コミットを小さく、かつアトミックにする
- コミットメッセージの中で、変更の「内容」と「理由」を説明する
[1] によれば、上記により以下のメリットが受けられます。
上記で確立したガイドラインを使用すると、コードレビュー、バグの発見、根本原因の分析など、一般的なソフトウェア開発タスクの課題を軽減することができます。
以降、原文からかいつまんで概要のみここにします。詳細や実際どのGitコマンドを叩けばいいのかなどは、原文を読んでいただければと思います。
コミットをストーリー仕立てにする
コミット間の流れに一連のストーリーが無いと、コミットを追うことは常にコンテキストスイッチを伴い、レビュアーの脳に多くの負担をかけてしまいます。逆に言えば、ストーリーに沿ってコミットを構成すれば、認知負荷が低くなるということでもあります。
以下によりこの問題を回避します
- アウトラインを書き、PRのDescriptionにそれを記載する
- 1ブランチで行うのは、1つの概念に留める
- コミットは、バグフィックス、リファクタリング、スタイル変更、機能など、種類別のブロックとして扱う。 *例えばリファクタリングと機能実装は明確に分ける
ストーリーに乗っ取り、Gitをrebaseする例
- Create the basic script (no options, just read & display the image).
- Add --output option.
- Add image manipulation options (--invert and --grey/--gray).
- Add GitHub Actions CI for basic linting.
コミットのサイズを認知しやすい単位にする
開発者はコミット単位を小さくすることを好むと思いますが、まとまりのないあまりに小さいコミットはレビュアーに逆に負担をかけてしまいます。各コミットを「スモール」かつ「アトミック」にすることで、この問題を回避することができます。
- スモール: スコープが最小限のもの、つまり「ひとつのこと」
- アトミック: 安定した独立した変更の単位。
若干理解づらいのですが、他の変更を加えることなくそのコミットにロールバックしても機能することです。 ACID特性のAと同じですね。
認知しやすい単位に、コミットを分割する例
認知しやすい単位に、コミットを統合する例
コミットメッセージの中で、変更の「内容」と「理由」を説明する
こちらはわかりやすいと思いますが、メッセージにWhatとWhyを書きましょう、という話です。以前@t_wadaさんも似た話をされていました。
以下をコミットメッセージに含めるようにしましょう。
What
- 意図
- どのように実装したか
Why
- 背景
- なぜこの変更を行うのか
例として、以下のようなメッセージが記載されていました。
Add '--gray' option alias for '--grey' Include '--gray' as an alternative
日本語だと、greyのtypoであるgrayもオプションとしてサポートするたに、'--gray'エイリアスを追加する、あたりでしょうか。ナゼとナニが含まれている文になっているかなと思います。
コードレビュー
履歴自体を資産として考えるのであれば、きちんとメンテがされている必要があります。そのため、コードレビューでは上記のガイドラインにコミットが従っているか、もレビューし、違反している場合はコミットの修正を求めましょう。手間ですが、これも後世のためです。
終わりに
こちらのガイドラインは、人が入れ替わったり、それなりに歴史あるプロダクトに関わっている方は、結構納得できる内容なのではないかなと思います。後世の人間とのコミュニケーションだと考えて、キレイなログを残していきましょう。
私自身もコミットログにはそこまで気を使えていないので、もっとrebaseやpickを使っていこうと思います。