リモート開発メインのソフトウェア開発企業のエンジニアブログです

GitHub の Pull request は Squash and merge にしてみている

皆様、あけましておめでとうございます。今年もよろしくお願いいたします。

新年1発目の記事は、表題にある最近取り組んでいるプロジェクトの GitHub 運用について書きます。

GitHub ではリポジトリの設定で、Pull request のマージ方法を選択できますが、そのプロジェクトではここ1ヶ月ほど “Squash and merge” のみを許可する運用をしています。

※コミットメッセージは “Pull request title and description” に設定してあります。

この設定にしておくと、Pull request のマージ時にターゲットブランチへはマージコミットが Push されるのではなく、トピックブランチの一連のコミットが設定通りに Pull request のタイトルと description をコミットメッセージとして単一のコミットに Squash され、ターゲットブランチはそれを Fast-forward します。(マージコミットは作られません)

これにより、Pull request のコミットログの形式に気を遣う時間からある程度解放されます。一昔前は Squash はタブー視されていた様な気もしますが、案外悪くないと言う所を今回紹介できればと思います。

経緯

最初からそうしていたわけではありません。はじめはデフォルトのマージコミットを採用し、各 Pull request で適切な粒度でコミットを区切り取り込んでいました。

しかし、関わる人の数が増えると当然技術レベルや Git の運用経験にばらつきが生じます。
Git のコミットログに関する議論は多々あるのでここでは割愛しますが、適切な粒度でコミットを切ることは、それなりの技術力とプロジェクトへの理解が求められます。
トピックブランチを作る際、そのブランチで達成すべき内容と、それを実現する明確な技術的指針が必要です。もちろん、最初は適当にコミットを切っていき、後で rebase や soft-reset でコミットを整形する手もありますが。

こうした経緯があり、コミットログの運用をチームで共有しようとも考えましたが、年末に会った知人から Squash and merge 運用がうまくいっているという話を聞き、真似してみることにしました。

良かったこと

1ヶ月使ってみた感想として、長所と短所をまとめます。

1. メインブランチのコミットツリーがシンプルになった

マージされた Pull request の数だけコミットが増えます。コミットツリーのログが少なくなり、各コミットのメッセージは1行目に Pull request のタイトル(と番号)が入るので履歴が分かりやすくなります。

2. Blame で経緯が辿りやすくなった

1に関連して、気になる変更箇所の Blame がシンプルになります。全てのコミットが Pull request に紐づいているため、その変更を行った Pull request の特定が容易になります。ただし、コミットの粒度が大きいため、なぜその変更が必要だったかをどこかで明確にしなければならない場面もあります。この辺りは後述します。

3. Pull request のコミット整理が必須ではなくなった(※ただし、ある程度はするべき)

レビューで指摘が入った後の修正コミットが発生すると思いますが、その際「指摘点を修正した」というようなコミットメッセージは親切ではありません。コミットの変更内容を1行目に簡潔に書き、2行目以降で経緯を述べるのが良いです。
あるいは、指摘が入った箇所に関するコミットを rebase して Force push すると履歴が綺麗になりますが、コミットの粒度によってはレビュアーの再確認の負担が高まります。

また、そもそも適切な粒度でコミットを毎回切るのは多少なりとも脳のリソースを消費するので、それであれば (どうせ Squash するので) あえて多少汚いコミットログでも許容しようと言う考えができます。

ただし、メインブランチでは Squash されていても Pull request 上では Push されたコミットログが残ります。後で Pull request を振り返る際の負担を軽減するために、(可能な範囲で)最低限の整理は必要です。「wip」や「一旦コミット」「今日はここまで」といった日記的なコミットは避け、「指摘点を修正した」といったものであれば許容範囲内としました。

気をつけるべき点

この運用でデメリットがまだ明確になっていないため、ここでは言及できませんが、注意すべき点はいくつかあります。

1. Pull request の粒度は適切に

コミットの粒度に気を使わなくても、Pull request の粒度には気を配る必要があります。このプロジェクトでは Revert できる単位を心がけています。ある機能の追加や変更で Revert が必要になった場合、Pull request ごと Revert できるようにしておくと、その後の運用が楽になります。

2. 直接関連がない変更はコミットを分ける

Pull request で行う作業の一部に、他にも影響がある変更が必要になることがあります。例えば設定ファイルによる並列数の調整などです。そうした変更は Pull request 内でも1つのコミットにまとめましょう。後で Revert したい場合にコミット単位でできるからです。
理想は、その変更自体について別の Pull request を作ることです。そのコミットを Cherry-pick して別の Pull request を作れば、元のトピックブランチのマージが長引いたとしてもその変更を先に反映できるかもしれません。Revert も簡単になります。

3. title は適切に、description はしっかり書く

冒頭でも示しましたが、デフォルトのコミットメッセージ設定は “Pull request title and description” にしましょう。Pull request のタイトルと description が記載されるようになります。チームで決めたフォーマットに従い、内容を詳細に書いておきましょう。Git 単体で見たときにこれが唯一の情報源となります。特筆すべき点はコミットだけでなく、description のどこかにも書いておくと良いでしょう。

まとめ

  • GitHub での Pull request の “Squash and merge” は思いの外有用です。Squash は避けるべきと言う意見もありますがプロジェクトによってはうまくいきそうです。
  • コミットメッセージの設定は “Pull request title and description” にしましょう。
  • Git 単体では情報は Squash コミットのみに残るので、title と description は適切に記しましょう。
  • Pull request に Squash 前のコミットログが残るので、最低限の整理はした方が良いです(“Update user.rb” や “指摘点を修正” などは許容範囲内です)。
  • Pull request に直接関連がない変更はコミットを分けるべきです。できれば Cherry-pick して別の Pull request を作りましょう。

← 前の投稿

PythonでChatGPT APIを使ってみる 第1回 基本的な使い方

次の投稿 →

TypeScriptとNode.jsを使ってSwitchBotのDeviceListを確認する(リクエストの署名)

コメントを残す