Git
バージョン管理

情報量の多い歴史を積み重ねるための実践的なコミット作法

はじめに

Git などのバージョン管理システムはソフトウェア開発に不可欠になりました。

バージョン管理は単なるバックアップや共同編集のためのだけのツールではありません。
ある意味、貴重な設計ドキュメントです。積み重ねたコミットは後からそのソフトウェアを読み解く人(未来の自分も含む)にとって非常に貴重な情報源になります。歴史には、最新のスナップショットだけを見てもわからないたくさんの情報が詰まっているのです。

また、歴史は一直線に進むわけではありません。ブランチや、不具合を起こしたコミットの取り消し、脆弱性修正のバックポートなど様々なことが起こります。

この記事では、将来の誰か(自分含む)のために、またさまざまな操作のために、私が普段コミットするときに気をつけていることを整理してみます。

なお、特定のバージョン管理システムの話はしていないつもりですが、どうしても Git を前提にしてしまっているかもしれません。

コミットログをちゃんと書く

まあ、みんなわかってますよね。よく語られている話題なので簡単に。

  • まとめ を書く。コードの詳細を読まなくても何のコミットかわかるように。
  • What より Why。 コードを見てわかることより、コードを見てもわからない、変更の理由のほうが大事。

というのを意識しつつ、「後で見てもなんでこんな変更してるのかわからないだろうな」と思うなら詳細に書けばよいし、自明なら簡潔に、でよいと思います。

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

また、そのリポジトリのローカルルールや慣習は確認しておきましょう。

  • 必ず英語で書く
  • バグトラッキングシステムのチケット番号を入れる

など。

ひとつのコミットに複数の内容を混ぜない

論理的に違う内容をひとつのコミットに 混ぜない
これは typo の修正など、些細なものでも同じ です。機能追加と typo 修正は混ぜてはいけない。

typo に気がついたときに直すのはよいこと (ボーイスカウトルール) だと思いますが、コミットは分けましょう。その変更が間違っていたら後から revert (取り消し) するかもしれません。一緒に typo 修正したのまで一緒に取り消されてしまいます。

空行やスペースの追加・削除など、(特にエディタの設定によっては)いつのまにか入ってしまうこともあるでしょう。こういうのも混ぜないようにしましょう。余計な変更が入っていると、後からその変更を revert したり別のブランチに取り込んだりする際にコンフリクトしやすくなります。

コミット (や push) の前に diff を確認する習慣をつけるとよいです。

機械的な変更は独立したコミットにする

ファイル名変更、クラス名変更といった、機械的に処理できる (でも変更量は大量になりがちな) 変更と、ややこしいロジックの変更は別コミットにするといいでしょう。後者の重要な変更内容が、前者の大量の変更に埋もれてしまうのを防ぎます。

コードレビューもしやすいです。

なんとなくコメントアウトしない

変更前のコードをコメントアウトして残したりしていませんか ?
それはバージョン管理システムの仕事です。いつでも古いコードは参照できるのだから、不要なものはばっさり削除しましょう。もし残しておく何らかの意味があるのなら、理由をコメントしておきましょう。

これ、変更の内容に自信がない人がやりがちです。コードレビューしてもらうなど、別の方法で確信を深めるとよいでしょう。

ソースコードに変更履歴を書かない

こういうやつです。

// 2018/02/03 〇〇を変更 (yamada)
// 2017/12/24 △△を追加 (tanaka)

20世紀にはよく見かけました。さすがにもういないですかね…。
これもバージョン管理システムの仕事です。

外部からファイルを取り込むときは変更ゼロでまずコミットする

外部ライブラリのとあるファイルだけ利用するとか、外部ベンダーや他チームからリリースされたファイルを取り込むなど、自分が作ったのではないファイルをリポジトリに取り込むことがあります。

このとき以下のようにしましょう。

  • まず 一切の変更をせずに コミットしましょう。変更が必要なら別コミットで。いきなり自分の変更を加えてしまっては、あとから何を変更したのかわからなくなってしまいます。
  • どこから取り込んだのか、トラッキングできる情報 をコミットログに含めましょう。ソフトウェア名、バージョン、URL、commitid など。

習慣になってしまえば簡単なことですが、意外にできていない人を見かけます。

同様に、ツールで生成したファイルをコミットする際や、リポジトリの統合・引っ越しなどのときにも上記の習慣は有益です。
また、何らかの理由でバイナリファイル(ビルド成果物)をリポジトリに入れる場合にも、元となったソースコードとそのバージョンは何か、など来歴がわかる情報をコミットログに入れましょう。

ライセンスが異なるファイルは分離する

外部からのファイルを取り込む際にはライセンスに注意して、ライセンスの異なるファイルはできるだけ別リポジトリ・別ディレクトリに分離するようにしましょう。

ライセンスが異なるファイルが混在する状況は危険です。知らぬ間にライセンス違反を犯すリスクが高まりますし、利用者にも管理の負担を強いることになります。

# (コミット作法というよりソフトウェアの構成管理に関する話題ですかね)

「本家」があるときは変更を最小限にする

どこか「本家」の開発元があって、それを変更して利用している場合。
「本家」の最新版をマージする際にコンフリクトが発生しにくいように工夫しましょう。

  • 変更は別ファイルにして、その言語の include 機能で取り込むなどする
  • 行は変更をできるだけ避ける。行の追加で対応する。
  • ファイル・行は削除しない

など。いつもとは変更方法も変わってきます。

こういう小手先が通用しないぐらい変更するなら、 Pull Request を出して「本家」に取り込んでもらったほうがよいですね。

まとめ

自分が習慣にしているコミット作法を整理してみました。

ソフトウェアはちゃんと動くことが一番重要です。最新のスナップショットが正しければいいのですから、コミット作法は直接的にはそれには寄与しません。
でも、長い目で見れば、よいコミットは確実にチームの生産性や情報伝達を改善に寄与します。未来への投資だと思って誠実に少しずつ歴史を積み重ねましょう。