git の commit がぐちゃぐちゃになった際の整理方法

概要

本記事は rebase で運用するリポジトリでコミットがぐちゃぐちゃなってしまい、コンフリクト対応に苦労した自身の対応記録になります。

上記を回避するには、コミットの整理が有効です。

コミットを整理するには git rebase -i が使えます。ローカルブランチでのコミットは細かくしても OK ですが、リモートへ push する前にコミットを整理する際に使うと良いです。理由は、整理せずにコミットすると、不用意に触ってしまったファイルなどがあるとコンフリクトのリスクが高まり開発効率が落ちるためです。

背景

まずは rebase をうまく使いこなせていなかったことで、下記のようなブランチになってしまった。

  • 自身の変更と関係のないコミットが含まれる

    Image from Gyazo

  • 複数ファイルをいじったコミット(触った後に元に戻す)があり、コンフリクト多発

そもそもどうすべきだったか

  • git rebase の意味を把握する

    rebase は自分の変更を後ろに足すという流れなので、複数ファイルを触ったようなコミットがあるとコンフリクトが発生しやすくなります。よって、後述のコミットの整理を行うことでそうした履歴を残さないのが重要

    image.png https://www.sejuku.net/blog/wp-content/uploads/2018/09/git-rebase3-640x360.png

  • コミットを整理する

    上述の通り、コードが固まるまでは、コミットを細かくするのは別に構わないですが、ある程度形になってきたら、コミットの整理が必要。上述の通り、コンフリクト発生予防が期待できるためです。

    コミットをまとめるのは、git rebase -i <ひとまとめにする地点の一つ前のコミットID> で実現できる。下記の例だと、ブランチAの前の『開始地点』コミットを指定する。

    image.png https://www.sejuku.net/blog/wp-content/uploads/2018/09/git-rebase6-640x360.png

    ローカルブランチからリモートへ上げる前に必ずコミットを整理したい。

で、ぐちゃぐちゃになった時にどうするか?

対応方法は大きく2つある。いずれも新規ブランチを main から立てるところは変わらない。その後の作業は次のパターンがある。

  • 変更コード内容を手作業で貼っていく

    Github なら『Files changed』タブの内容を見ながら、変更コードをペタペタと新しいブランチに貼っていく。この方法は、後述の cherry-pick を知らなくてもできるので、パッとできる方法で手軽だと思います。

  • cherry-pick で対応

    必要なコミットを指定して取り込んでいく。git cherry-pick <取り込むコミットID> でコミットを取り込むことができる。cherry-pick という git の機能を活用するので、少し慣れた人向けだと思います。操作の流れは下記のような感じかなと思います。

    1. リモートの main ブランチから新しいローカルブランチBを立る
    2. ぐちゃぐちゃになったブランチAから必要なコミットを git cherry-pick <commitID> で取り込む
    3. 最後に、git rebase -i でコミットを整理する

    上記の流れを図示してみると下記のような感じ。

    Image from Gyazo

    Image from Gyazo

上記のようにすることで、ぐちゃぐちゃになったコミットを整理できるようになる。コミットが綺麗にできたら git push origin <ブランチ名> --force-with-lease でプッシュしてあげれば良い。

実際にやってみる

  1. まずはリモートリポジトリの main ブランチから新しいブランチを立てる。
  2. 必要なトピックを git cherry-pick <取り込むコミットID> で抜き取る

    元々70個あったコミット(自身のコミット以外が混ざっている状態)から、自身の変更分のみを抽出し、下記のような感じにしました。

    Image from Gyazo

  3. cherry-pick だけで対応できていない部分の修正

    FBC アプリの場合、main が毎週更新されるので、対応できていない部分が発見されたら対応する(今回に限らず、いつも通りの作業)

  4. git rebase -i でコミットを意味のある単位にまとめる

    今回は、main ブランチのコミットを開始地点として指定して、git rebase -i を実行します。すると、次のような画面になる。

    Image from Gyazo

    上記の pick となっている部分はコミットを残す部分で、まとめたいコミット部分は squash にしていく。ポイントは古いコミットにまとめていくので、まとめる側の古い側を squash にする。今回は次のように修正。

    Image from Gyazo

    次にコミットメッセージを修正していく。上記では、コミットを3つのコミットにまとめるので、メッセージも3回更新する。更新完了すると次のような感じになる。

    Image from Gyazo

    コミットがまとまったかを git log --graph で確認してみます。

    Image from Gyazo

    十数個あったコミットが1つにまとまりました🙌

ここ2週間くらい、rebase のコンフリクトに苦しみましたが、そのおかげで理解が深まった気がします。今後は無闇にリモートから rebase せずにまずはローカルを整理してから対応をしていこうと思いました😅

Git 操作でやらかした場合

git reflog が使える。上記を実施している際にも、何度も git 操作をやり直すことになったんですが、git reflog がめちゃめちゃ優秀でした👀今後も何かあった時には、頼ろうと思いました。

参考