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 運用を徹底するか、コンフリクト解消のマージコミットはコミットメッセージを明確に記載する等の工夫をしましょう。


Facebooktwittergoogle_pluslinkedintumblrmail

Trackback

Comment

  • 1.
  • 匿名
  • 2017/06/09 02:36

マージコミットの用途は、その反映が何月何日何時何分に行われましたよという記録が残る部分ですね
これがないと、コミットの日付しか残らないので、本番リリース前にコミットし度忘れし本番リリース後にpull –rebaseした場合、履歴上ではあたかも、本番リリース前には反映済みの日付に見えるが、それは自分のブランチだけの話であって、リリースブランチにマージしたのは、リリース後でした・・・ってことに気付けない
マージログは慣れてしまえば、普通に読めるのであまり–rebaseはお勧めできないですね

日付で見る場合もあるかと思いますが、git log でのデフォルトの表示順はコミット適用順なので気付けないということも無いかと思います。各種 git クライアントのデフォルト表示順がどうかは把握していないので日付を優先して表示するクライアントもあるかもしれませんが、個人が利用している git クライアントの都合で全体の履歴に影響を与えるほうが不健全に思えますし、リリースブランチを運用しているのであればリリースブランチの履歴を確認する、リリースブランチとカレントブランチの差分を取る、等がこの場合の確認方法としては良さそうです。

記事中で意図しているのはマージログ自体の読み易さでなく、頻繁に pull が行なわれる場合において大量にマージログが作成されコミット履歴が見辛くなることへの懸念です。これはプロジェクトの参加人数等にもよるのでケースバイケースではありますが、一般的に公開されているリポジトリにおいて pull で作成されたであろうマージログはあまり見ないという慣例的な面もあります。

名前
E-mail
URL
コメント