近年ではエンジニアの必須スキルとなった Git の活用法について、コード品質を向上させるポイントを 3 つ紹介します。エンジニアになりたての方や「Git は使っているけど自信がない」という方にも、ぜひ役立てていただければ幸いです。
今回、登場人物を大きく以下の 3 つに分けます。
- 実装者
- レビュアー
- 他のエンジニア
コミットメッセージに Prefix を付ける
コミットメッセージに feat:
や fix:
などの Prefix(接頭辞)を付けることで、修正内容を一目で明確に伝えられます。
一般的に共通して使われ、使用頻度も多い Prefix は以下の 4 つです。
feat:
新しい機能の追加fix:
バグ修正refactor:
仕様に影響しないリファクタchore:
CI/CD やライブラリなどの基盤修正
チームで共通の仕様が決まっていない場合は、Conventional Commits のガイドラインを活用すると、業界標準に基づく統一的なメッセージが書けます。
Prefix を付けることで得られるメリットの 1 つは、後からコミット履歴を確認する際に、修正内容が一目で把握できる点です。
さらに、どの Prefix を付けるかを意識することで、余計な修正がコミットに混入するのを防ぎ、1 コミットあたりの修正差分を少なく抑える効果もあります。
コミット履歴を確認するのは、レビュアーや、数日後・数カ月後の自分自身かもしれません。そのとき、コミット単位の修正量が適切に抑えられていれば、修正内容を素早く正確に把握することが可能です。
修正内容を素早く正確に把握できれば、レビューで仕様の確認に留まらず、パフォーマンスや処理改善の議論が可能になり、コード品質の向上に繋がります。
コミット単位は機能のまとまりを意識する
私がレビュアーとして実際に見た、改善の余地があるコミット履歴の例を 2 つ紹介します。
例 1:コミット履歴が作業ログになっている例
5 refactor: ビューの処理をリファクタ
4 refactor: コントローラーの処理をリファクタ
3 feat: 12/22 までの作業分コミット/一旦完成
2 feat: 12/21 までの作業分コミット
1 feat: 12/20 までの作業分コミット
これは、実装者の作業の単位でコミットが作られています。1~3 のコミットはその日の作業単位でコミットされています。
レビュアーや他のエンジニアが関心があるのは、どのようにして機能が追加されたかどうかです。
そのため、このようなコミット履歴だと、コミットごとに修正差分を見るときに不完全な差分を見ることになり、実装の全貌を見るためには全ての差分(GitHub の File Changes)を見ることを強いられてしまいます。
そのため、このような自身の作業ログを保存しておくようなコミット単位は避けましょう。他のエンジニアは、あなたがその日どこまで進めたかには関心がありません。
TODO コメントを残した仮実装のコミットを追加し、後で本実装するケースをよく見かけますが基本的には避けるべきです。仮実装のコードは動作が保証されず、レビュアーが本実装のコミットと併せて確認する手間が増えてしまいます。
4~5 のコミットは、1~3 までのコミットのリファクタリングになっています。
レビューに出す前にリファクタリングを行う意識はとても素晴らしいですが、リファクタリング対象のコミットが同一の PullRequest にある場合、分けておく必要はありません。1 つのコミットにまとめてしまいましょう。
例 2:指摘に対する修正がコミット履歴にある例
5 fix: 一覧コントローラーのバグ修正
4 fix: 一覧ビューの指摘修正
3 fix: 一覧コントローラーの指摘修正
2 feat: 一覧ビューの新規作成
1 feat: 一覧コントローラーの新規作成
この例では、1〜2 のコミットは機能ごとにまとまっており非常に見やすいです。しかし、3〜5 のコミットはレビュー指摘やバグ修正が個別に積まれており、履歴が冗長になっています。
1〜2 の後、レビュー指摘を受けて 3〜4 の修正を行い、最終的に 5 でバグ修正を行ったというストーリーが想像できます。しかし、こうした履歴は実装者やレビュアーには有用でも、他のエンジニアにとっては不要な情報となりがちです。
そのため、3〜5 のようなコミットは残さず、レビューでの修正内容やバグ修正は元のコミットにまとめる方が望ましいでしょう。これにより、履歴が簡潔になり、全体の把握が容易になります。
修正内容を別コミットに分けておかないと、再レビュー時に指摘に対する修正差分が確認できないという問題があります。この問題の解決策は次のポイントで紹介します。
fixup と rebase でコミットログを綺麗にする
コミット単位を意識しても、途中で修正が必要になる場合があります。その際に履歴を整理するための便利な機能が、fixup
と rebase
です。
先に述べた以下の 2 つのポイント:
- コミットメッセージに Prefix を付ける
- コミット単位を機能のまとまりで意識する
これらを常に守るのは難しい場合もあります。たとえば、実装途中で漏れに気づいたり、レビュー指摘に対する修正をコミットとして積むケースです。
特に後者のケースは、レビューを効率的に進めるべきにもむしろ積極的に行うべきです。
rebase
は非常に色々なことができる機能なので詳細は割愛し、今回は限定的な使い方の紹介に留めます。
指摘に対する修正を行う場合、
dfc67acb feat: 一覧コントローラーの新規作成
1f315272 feat: 一覧ビューの新規作成
一覧コントローラーに修正が必要な場合、該当のコミットに fixup
を利用して修正を加えます。
git commit --fixup dfc67acb
これにより、以下のような fixup!
付きのコミットが生成されます
4320bf0d fixup! feat: 一覧コントローラーの新規作成
レビュアーにはこの修正コミットを見てもらい、再レビューをお願いします。
レビューが完了したら fixup
で積んだ修正コミットを main ブランチにマージする前に、git rebase
を使用して整理します。
git rebase --autosquash -i 1f315272
このコマンドで、fixup!
付きのコミットが元のコミットに自動的にまとめられます。これにより、main ブランチの履歴がすっきりし、他のエンジニアにとって見やすい履歴を保つことができます。
rebase
を行ったことによりリモートとコミット履歴に差異が発生するため、push
する際は --force-with-lease
を付けて強制 push を行います。
git push --force-with-lease
git push --force-with-lease は慎重に扱うべきコマンドです。特にチームでの利用時は、運用ルールを明確にし、誤操作を防ぐ仕組みを整えることが重要です。
レビュー中は修正コミットを fixup
として積み、マージ時に rebase
でまとめる。この手順を踏むことで、レビュー効率を高めつつ、main ブランチの履歴を綺麗に保つことができます。これにより、他のエンジニアにとっても理解しやすいコミット履歴を実現できます。
まとめ
Git のコミットを通して、コード品質の向上に繋がる使い方のポイントを紹介しました。
エンジニアの業務に占める割合は、コードを書くより読む時間の方が圧倒的に多いです(コードレビュー、仕様調査、バグ調査、etc...)。そのため、読みやすいコードや把握しやすいコミット粒度・メッセージを意識することは、コード全体の品質に大きな影響を与えます。
今回紹介したポイントを日頃の業務に活かし、より良いチーム開発を目指しましょう。些細な工夫が、コード品質とチーム全体の生産性向上に大きく繋がります。