Gitリベースの使い方:競合解決とコミット履歴の整理方法

スポンサーリンク

この記事では、Gitリベースの基本操作とその利点について詳しく解説します。git rebaseコマンドを使ってブランチを整理し、コミット履歴を直線的に保つ方法を紹介。競合が発生した際の解決手順や、インタラクティブリベース(git rebase -i)を利用してコミットをまとめるテクニックも説明します。効率的にブランチを管理し、整理されたコミット履歴を維持するための具体的な手法を学びましょう。

パッチを取得するブランチを指定し適用して現在のブランチのパッチを適用 (git rebase <ブランチ名>)

以下のようなコミット履歴を想定してgit rebaseを行います。

masterブランチでgit rebaseコマンドを実行します。リベースを行うとき、いくつかのファイルが競合する例をします。
まず、git rebaseで競合したときに使う特有のコマンドを紹介します。

コマンド説明
git rebase --continue続けて競合を解決する操作を行う
git rebase --skipあるコミットでの競合の解決をスキップ
git rebase --abort競合中のリベース操作を中断してリベース前まで操作を元に戻す

masterブランチからgit rebaseでb1ブランチを引数にして、リベースを行います。結果として出来上がるmasterブランチはb1ブランチを適用されてからmasterブランチのコミットが適用されたものになり、b1ブランチの先を作成したようなイメージになります。

上の例では一つのコマンド毎に出力が多く何のコマンドを行っているか分かりにくいと思うので、上の例のコマンド操作をまとめると以下のようなコマンドを使用しています。基本的にmerge操作の競合処理と似たような感じで処理していきます。

最終的なコミット履歴は以下のようになります。

一応補足として、リモートブランチを除いたブランチを確認すると一直線のコミット履歴を見ることができます。

リベース操作の説明としてこれで終わりになりますが、これをリモートブランチにプッシュしようとして簡単な操作を行うとb1ブランチにつなげる形でコミット履歴がプッシュできるようにできます。これを意図したものかどうかはわかりませんが、masterブランチを主流の流れだとするとおそらく違うものになると思います。

masterブランチにつながるようにリベース

以下のコミット履歴に戻ってやり直します。これは裏であらかじめリポジトリをコピーしたものを使用しています。

masterブランチにつなげるようにするには、一度b1ブランチに移動してからリベース操作を行う必要があります。出力自体は上の例と似たようなものになるので操作部分のみを記述します。

このようにするとコミット履歴は

のようになります。次にmasterブランチに戻り、git mergeを使い、fast-forwardでmasterブランチを進めます。

そうするとmasterブランチのコミット履歴は

のようになります。この状態でpushを行うとmasterブランチの方にコミットを追加できるようになります。

リモートのb1ブランチを削除したい場合は

で削除できます(リモートリポジトリの名前としてoriginを利用しています)。その後にローカルのブランチは

で削除できます。

最終的に残るコミット履歴は以下のようになります。

ただし、コミット履歴からb1ブランチの流れが消えてしまうのでリモートブランチで複数のブランチを管理している場合、ブランチを統合するような目的だとrebaseではなくmergeで操作を行ったほうが良いかもしれません。または、複数人で共有するようなリモートブランチでメモのようなブランチを管理せずに重要なブランチのみを管理しても良いかもしれません。
リベース操作を行うのに都合がいいところとしてgit pullを行うときにリベースでリモートリポジトリの内容を取り込む方法があります。これはリモートでの作業の例で説明しています。

リモートでの作業の例
ここではリモートリポジトリとしてLocalプロトコルを用います。ローカルリポジトリはLocalReposディレクトリに、リモートリポジトリはRemoteReposディレクトリで管理するとします。 リモートサーバーの確認 (git remot...

適用するパッチを対話的に選択(git rebase -i <ブランチ名>)

以下のようなコミット履歴に対して、git rebase -iの例を示します。この例の意図はmasterブランチの後にb1ブランチのコミット内容を繋げる操作になります。

git rebase -iで適用するパッチを選択するためのエディタが開きます。

エディタが開いたら、以下のような内容を編集してgit rebase -iの動作を変更できます。
編集する部分は'pick'と書かれている部分で、これはコマンドになります。対応するコミットIDやコミットメッセージがあるので、行いたいコマンドに変えていきます。
また、コマンドの種類はコメントの部分で書かれています。

この例では7と8番目のコミットを6番目のコミットに統合したいと思います。7と8番目のコミットをs(squash)に変更し保存して終了します。

その後は、通常のリベース操作のように競合があれば解決していきます。以下は今回の例で利用しているコマンドの流れになります。

それらのコマンドを利用していった流れの全体は以下のようになります。

リベース操作が完了した後のリモートブランチを含んだ全体のログは以下のようになります。

また、リベースしたブランチのみに注目したコミット履歴は以下のようになります。

この後の操作は、ローカルのmasterブランチを進めて、リモートリポジトリのmasterブランチにプッシュすることになるでしょう。

コミットをまとめる

git rebase -iはコミットをまとめるのに利用できます。例えば、リモートリポジトリにまだプッシュを行っていないコミットで、機能的に同じ部分のコミットであり軽微な修正のコミットを出してしまったときにコミットをまとめたい場合があります。そのようなときに使用するのに便利です。
以下のようなコミット履歴を例にします。

git rebase -iで現在のブランチの最新のコミットから2つ前(この例の3b5fb54)を指定することで、その指定したコミットを含まずに最新のコミットまでの間のコミットでエディタが開きます。

または、コミットを直接指定して、

または、まとめたいコミットまでの範囲で一番古いコミットを直接指定して、そのコミットに直前を表す(^)をつけて指定する方法もあります。

これらはすべて、エディタで以下のような内容のものが開かれます。

git rebase -iで一番最初のコミットを選択したい場合は--rootオプションが利用できます。

また、この例で一番最初のコミットや最初から2番目のコミットを修正した場合、その修正をリモートリポジトリに反映させるためには強制プッシュを行わなければいけないところに注意が必要でしょう。

git rebase -iでまとめた結果として

としたとき、これはリモートリポジトリのコミットをいじっていないので通常のプッシュでリモートリポジトリに記録できます。

これはローカルリポジトリにあるコミット履歴を整理したい場合に利用できるテクニックになります。