💡

マージコミット入りのPull Requestで困ったら: git merge --squashでコミットをまとめよう

に公開

はじめに

Pull Request(以下、PR)をレビューしてもらう前にコミットを整理しておくことは、レビュワーの負担を減らす上で非常に重要です。一般的に、コミットをまとめる方法としてよく紹介されているのが git rebase -i HEAD~{N} を使う方法です[1]。この方法は、1つのコマンドで簡単にコミットをまとめられるため、ベストプラクティスとして広く知られています。

ただし、この方法は途中にマージコミットが含まれている場合、扱いが一気に難しくなります。PRのレビューを依頼する前に git rebase -i を使ってコミットをまとめようとした結果、base branch の変更まで一緒にまとめられてしまい、PR上から見えるファイルの差分が本来よりも大きくなってしまった、という経験がある方もいるのではないでしょうか。

そこで今回は、私が普段からよく使っている git merge --squash を使ったコミットのまとめ方をご紹介します。Gitに慣れたエンジニアにとっては当たり前のテクニックかもしれませんが、ネット上であまり紹介されていないため、誰かの助けになるのではと思って記事にすることにしました。

手順

たとえば、以下のようなPull Requestがあるとします。レビューを依頼する前に、このPRの複数のコミットを1つにまとめたいと考えます。

このとき、コミットツリーは以下のようになっています。途中でマージコミットが入っているのが特徴です。

このような場合に、きれいにコミットをまとめる手順を以下に示します。前準備として、ローカルのブランチをリモートと同じ状態にしておきます。

  1. まず、ローカルでmainから新たに適当なブランチ(ここではchore/sqhash-commitとする)を切ります。
git checkout main
git checkout -b chore/sqhash-commit
  1. 次に、chore/squash-commitブランチ上で、feature1 ブランチを squash merge します。これにより、feature1 の変更内容がすべてステージされた状態になりますので、それをコミットします。
git merge --squash feature1
git commit -m "feature1"
  1. 最後に、作成した1つのコミットを、元の feature1 ブランチにforce pushします。
git push -f origin HEAD:feature1    

これにより、PRのコミットを1つにまとめることができました。PRの差分(Files changed)は元のPRと変わりません。

補足

  • もちろん、途中にマージコミットが入っていない場合でも、今回紹介した方法でコミットをまとめることができます。
  • 今回は、すべてのコミットを1つにまとめる例を紹介しましたが、git reset --hard {commit_hash} などと組み合わせることで、任意の連続したコミットだけをまとめることも可能です。

最後に

基本的には、git rebase -i HEAD~{N} をこまめに使って整理していくのが王道です。ただし、途中にマージコミットが入ってしまった場合でも、今回紹介した git merge --squash を使えば、安全にコミットまとめることができます。

脚注
  1. rebase -i でコミットをまとめる ↩︎

Discussion