pyてよn日記

一寸先は闇が人生

Git でコミットする時のルールを言語化してみた

開発を行う際,多くの開発者がソースコードバージョン管理システムを利用している.筆者自身も例に漏れず,その一つである Git を利用している.

プログラミングを勉強し始めてから 1 年 8 ヶ月ほど経ち,「言語化していないけど,コミットをする時になんとなくこれは意識しないといけないな」という知見が徐々に溜まってきたため,本記事ではそれらを言語化してみた.

概要

Git を使用していく上で意識したい「コミットのルール」を整理した.具体的には,コミットメッセージのフォーマットやコミットの粒度をどうするか,などについてである.

本記事の目標

本記事の目指すところは,「1 週間後の自分を含めた『他人』がコミット履歴を見た時に,ソースコードの変更の意図が明確に伝わるようなコミット履歴を作れるようになる」である.

最終的には「レビューのしやすいコミット,コミット履歴を作れる」が目標だが,これに関しては,pull request の話を絡めざるを得ないために話が複雑になってしまうことや,筆者の経験が不足していることなどの理由により,本記事では触れることができなかった.

注意

  • 現場の方からしたら物足りないレベルかと思います.
  • あくまで個人的な経験の中で得た知見です.バイアスの塊な気がしてならないため,誤った認識,「これあんまり良くない」,「こうしたらもっと良くなるよ」等々あれば気軽にご指摘,コメントしていただけると幸いです.

コミットする時のルール

コミットする時のルールをまとめる.

コミットメッセージの言語

技術者の間で用いられる言語は基本的に英語なので英語を使った方が良い.ただし,自分の関わるプロジェクトに依る.

自分が決めたルールとしては以下 3 つ.

  • チームで決めた言語を使用する
    • チームで日本語を使うと決めたのならそれに従うべき
  • 出来る限り英語を使用する
    • 時と場合によってだが,世に公開したいリポジトリは英語必須.OSS も英語が多い(中国語も増えてる?).
  • 個人的な用途以外でしか使わないプロジェクトの場合,日本語を使っても良いことにする
    • 筆者の場合,個人用 Wiki とか日々のメモとかを Git で管理しているが,そういった個人的な用途のものをわざわざ無理に英語で管理する必要はないと考えている.効率が落ちるのは本末転倒

コミットメッセージのフォーマット

原則,以下のフォーマットを守る.

1行目 コミットの種類(後述):コミットの要約(タイトル、概要)
2行目 空行
3行目以降 変更した内容,理由を詳細に説明する

コミットメッセージを作成する際は以下を意識する.

  • コミットの what と why を必ず明確にする
    • 何を変更 / 修正したかを明確にする(機能,バグなど)
    • 何故変更 / 修正したかを明確にする

ただし,自明な内容のコミットの場合,1 行でも構わない(あまり無いと思うが,例えば add: .gitignore などは理由が自明なので 1 行で十分).

「一々 3 行以上のコミットメッセージ書いてらんねーよ」という方は(自分もそう),次節の prefix を導入するだけでも大分効率が変わると思う.

コミットの種類の分類と prefix

コミットの種類・意図を分類し,それを prefix という形でコミットメッセージから容易に読み取れるようにするのが目的.そのコミットがバグの修正なのか,コードの見た目を綺麗にするだけの変更なのかなど,何を意図しているかを prefix で適切に切り分ける(先述したフォーマットの 1 行目に記載する「コミットの種類」のことである.).

ここでは,「種類が多くなり過ぎず,且つ,コミットの内容が曖昧になり過ぎず」を意識して決めた.よく使われている(標準的な?) prefix を用いてはいるが,それぞれの使い方,切り分けは筆者自身の好み,考え方から作ったルールであるため注意.結局は一緒に開発する人との共通認識が保てれば良い(プロジェクトのドキュメントに書いておくのが良さそう?).

計 10 個の prefix を挙げる.

ファイル,ライブラリの追加・消去に関する prefix 3 つ

  • add:新規ファイル,ライブラリ追加(「ライブラリ」は「各言語の 3rd party 製のライブラリ」を想定.pip とか npm/yarn とかでインストールするもの)
  • remove:ファイル,ライブラリの消去
  • upgrade:ライブラリのバージョンアップ.

ユーザが利用する機能の追加・修正に関する prefix 4 つ

  • feat:ユーザが利用する機能の追加,修正に関するコミット.機能追加と新規ファイル追加が同時に行われるのはよくあることなので,featadd 相当のことをやっても良いとする(featadd の性質を内包しても良いとする).
  • fix:バグ修正
  • refactorリファクタリング(外部的振る舞いを保ちつつ,内部構造を改善する)
  • perf:パフォーマンス改善

設定ファイルなどの編集,修正に関する prefix 1 つ

  • update:設定ファイルの編集など,ユーザが利用する機能以外の部分での変更(機能部分は変更しないフレームワークミドルウェアに関する設定ファイルを想定.)

非機能に関するコミット prefix 2 つ

  • style:コードの見た目の変更(機能部分は変更しない).空白,フォーマット,改行,セミコロンなど.
  • chore:ビルドプロセスやドキュメント生成などの補助的なツールやライブラリの変更
    • Changes to the build process or auxiliary tools and libraries such as documentation generation
  • ci:CI の設定に関する変更
  • docs:ドキュメントの編集.

prefix が多いと面倒と思っていたが,最初にルールを決めてしまえば,むしろ細分化されていてた方が管理しやすそうだなと感じた.多ければ良いというものではないが,コミットの意図・内容が異なるものは適切に切り分けられる程度の prefix の種類は用意した方が良いと思う.筆者的には,「このコミットはこういう意図」というのを脳死で prefix に当てはめられるようになることが理想だと考えている.

正直 Angular の定義だと chorecidocs も含んでしまうので、そこは切り分けて「雑多な変更」を扱うと良いと思う。ファイル名の変更とかファイルの移動とかコメントを足したとか。

コミットの粒度

コミットの粒度については,1 コミットにつき以下の項目を満たすことを意識する.

  • 1 コミット 1 トピックが理想
  • 完結する機能単位でコミット
    • ただし,どの程度の大きさの機能なのかは場合によりけり(大きな 1 つの機能なのか,機能の一部分なのか).チームで共通認識を定めておけば OK.
    • ローカルで動作させた際,各コミットの時点ではエラーが出ない(テストが通るかまた別の問題)
  • diff を綺麗にする
    • 「内容に関わる変更」と「改行,スペースなどの見た目の変更」を出来る限り混同しないようにする.
  • git add . はダメ絶対
    • コミットする前に必ず GUI(私は Sourcetree を使用している),git diff コマンドなどを利用してファイルの差分を眺める.
    • diff を確認したら,行,「ハンク」単位でステージング -> コミット
    • 変更内容とコミットメッセージの内容を一致させる.1 つのコミットに複数の意図が混ざるとコミットの全体像を把握しづらくなる.

補足

コミットメッセージの時制

コミットメッセージの時制を現在形(というより命令形),過去形どちらにするのが良いかという問題があるが,Git の公式ガイドライン(line 135, 2020/02/27 時点)によれば,命令形で書くことが推奨されている

以下,ガイドラインの抜粋.

imperative-mood Describe your changes in imperative mood, e.g. "make xyzzy do frotz" instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy to do frotz", as if you are giving orders to the codebase to change its behavior. Try to make sure your explanation can be understood without external resources. Instead of giving a URL to a mailing list archive, summarize the relevant points of the discussion.

以下要約.

  • 変更内容を命令形で説明しろ
  • 変更内容を,コードベースに対して命令をしているかのように説明しろ.
  • 1 つのコミット内で説明が完結するようにしろ.
    • 外部リソースがなくてもコミットの説明が理解できるようしろ.
  • メーリングリストアーカイブの URL を提供する代わりに,議論のポイントを要約しろ

用語説明の補足.

時制に関する所感

コミットの行為自体過去のことであるため,過去形が直感的であると個人的には思う(その反面,-ed を付けると冗長で視覚的に煩わしいとは思う).しかし,命令形が推奨されるのであればそれに従おうかなと思うし慣れれば特に問題なさそう.チーム開発だとこういうのも細かく決められたりするのだろうか(プロジェクトでのコミットメッセージの規約的な?).

正直内容が明確に伝われば何でも良いとは思うが,時制とかフォーマットが揃ってると自分含め他人が見た時に分かりやすいし,ルールを決めとけば脳死で書けるというのが良い.

Work in Progress パターン

WIP の意味が分からなくて調べたのでメモ.

本記事と趣旨が微妙に異なるが,コードレビューを前提にした開発を行う際, WIP(work in progress,作業中)という文字を Pull Request(PR)のタイトルやコミットメッセージに含め,現在の作業の進捗度合いを可視化しながら開発を進めるという方法がある.

WIP という文字がコミットメッセージに付与されていると,その作業が終了しておらず,作業中であることが分かる.WIP が取れると作業終了を表し,レビュー待ちであるという状況が一目で分かる.開発フローは以下の通り.

  1. コンテキストの共有
    あらかじめ実装者とレビュワーが実装する機能の仕様,動作などを共有しておくことでレビューをスムーズに行えるようにする.
  2. 作業ブランチの作成
    特定のコンテキストに関するブランチを作る.ブランチ名はプロジェクト毎の取り決めに従う.feature/[機能]機能名/チケット番号 など.
  3. ファイル変更の無い空コミットを作り,リモートブランチへ push
    PR を作成するにはコミットが必要となる.
  4. PR の作成
    3 で作成したブランチを用いて PR を作成する.実装方針などのコンテキストを丁寧に書く.
  5. PR のレビュー後,実装開始
    コンテキストのレビュー後,実装を開始する.
  6. 変更内容のコミット,リモートブランチへ push
    コミットメッセージの先頭に [WIP] を付与する.
  7. PR の更新,レビュー,修正
    PR のタイトル,コミットメッセージなどから [WIP] を除去し,作業が完了したことをレビュワーに伝え,レビューを実施.必要に応じて修正.

以下の記事が詳しい.

終わりに

今の自分にとって,本記事の内容は守りたいルールであると同時に理想でもある.いきなり「他人が読みやすいコミットメッセージを書ける」,「適切なコミットの粒度で管理する」など出来るはずもないので,地道にこのルールを遵守するように心がけていきたい.

冒頭でも書いたが,当面の目標は「1 週間後の自分を含めた『他人』がコミット履歴を見た時に,ソースコードの変更の意図が明確に伝わるようなコミット履歴を作れるようになる」である.

参考

記事,資料

便利なサービス

GitHub のコミットメッセージを検索できるサービス.クエリ(fix など)を指定して例文検索として利用できる.