user icon

何故 git rebase は駄目で git pull –rebase はいいのか

git pull –rebase は便利ですが、rebase と言えば git rebase、これが割と敬遠されがちな声を聞くので –rebase オプションなんて本当に使っていいのか心配になることもあるかと思います。

私も普段は便利に git pull –rebase していますが、ふと git rebase の解説記事をみかけると毎度不安になりこの二つの仕組みを調べてしまうので、いっそのことまとめてしまうことにしました。

git rebase

以下のような状態のリポジトリがあったとします。

git-rebase-flow-rebase1

一番上はリモートの master、下 2 つはローカルで master と作業用 branch です。例えばローカルでブランチを作成して作業し、それを master に rebase する前に pull したところ、リモートの master に更新があった場合等ですね。

この状態で master ブランチから rebase-branch に対し rebase を行ってしまうと以下のような状態になります。

git-rebase-flow-rebase2

ブランチでのコミットがリモートから取得したコミットより手前に挿入される為、リモートに既にあるコミットのハッシュが変わってしまいます。ローカルとリモートが一致しない為 push 出来ないのですが、ここでよく分からず曖昧に git push -f をやると末代まで恨まれることとなります。

これが一般的に git rebase が敬遠される理由でしょう。

git pull –rebase

では git pull –rebase とは一体何なのか。以下のような状況を考えます。

git-rebase-flow-pull-rebase1

登場人物は 2 人、リモートの master ブランチとローカルの master ブランチです。ローカル master にコミットがありますが、リモート master にその手前に反映されるコミットがある場合です。

git-rebase-flow-pull-rebase2

その状態から git pull –rebase するとこのようになります。リモートの更新がローカルのコミットの手前に反映され、ローカルのコミットのハッシュが変わってしまいました。

git-rebase-flow-pull-rebase3

しかしハッシュが変わったコミットはまだリモートに存在していません。なのでここで push してもコンフリクトは発生せず、問題にならないというわけです。

ここで –rebase オプションの何が便利かというと、マージコミットが発生しないことです。pull してコンフリクトしない場合というのは結構多いですが、通常はその際にもマージコミットは発生してしまいます(ローカルでのコミットが無い等で fast forward マージになる場合を除く)。複数人が開発するプロジェクトで、各個人のローカルリポジトリの pull 状況を残したマージコミットは大半の場合不要でしょう。

補足

git pull –rebase が危険なケース(多分少ない)

こういうことを書くと結局よく分からなくなるのでは…と思いつつ、簡潔に。リモートリポジトリを複数持つリポジトリでは注意が必要です。仕組みは git rebase の項のローカルリポジトリをリモートリポジトリに置き替えて考えると分かり易いです。登場人物が 3 人以上になると危険ですね。

但しこの場合も push しようとするとリジェクトされるので、push -f さえしなければとにかく安心と考えることも出来ます。

git pull –rebase がコンフリクトした場合

こういった場合は git rebase –abort 又は git reset –hard HEAD して、通常の git pull を行いマージコミットを作成してもいいかもしれません。コンフリクトした場合の rebase 操作がややこしいというのもありますが、「コンフリクトをどのように解消したかを明確に残す」という意味でマージコミットを作成する意義がある為です。

但し pull した場合の空のマージコミットがリポジトリに大量に含まれている場合、この意味のあるマージコミットが埋もれてしまいます。git pull –rebase 運用を徹底するか、コンフリクト解消のマージコミットはコミットメッセージを明確に記載する等の工夫をしましょう。


Facebooktwitterlinkedintumblrmail