rebase後の強制プッシュ
以下のようにfeatureブランチをmainブランチにrebaseして最新のmainを取り込むことはよくあると思います。
$ git pull --rebase origin main
で、それをリモートにpushしようとすると、**fast-forwardできないからpushできないよ!**と怒られます。
$ git push origin feature1
To github.com:hitochan777/test.git
! [rejected] feature1 -> feature1 (non-fast-forward)
error: failed to push some refs to 'git@github.com:hitochan777/test.git'
(以下略)
これを解決するためには強制プッシュをするとうまくいきます。
git push origin feature1 -f
なぜ強制プッシュする必要があるのか
ポイントはpushはリモートブランチがfast-forwardできることを想定しているということです。
どういうことか、具体的に例を考えてみましょう。
origin/feature1
がC3を、feature1
がC5を指している状態を考えます。
C1--C2--C3 <- origin/feature1 (C5までfast-forwardできる)
\
C4--C5 <- feature1
この場合、origin/feature1
はC5までポインターを進められる(fast-forward)ので、
強制プッシュをしなくてもプッシュは成功します。
ではfeature1ブランチをorigin/mainブランチにrebaseしている場合はどうでしょうか。
C1--C2--C3--C6--C7 <- origin/main
\
C4--C5 <- feature1, origin/feature1
rebase後は次のようになります。origin/main
にrebaseをするとfeature1
とorigin/main
の共通の祖先からorigin/mai
が指すコミットまでのコミットのコピーが作られます。下図ではC4', C5'としています。
C1--C2--C3-------C6--C7--C4'--C5' <- feature1
\
C4--C5 <- origin/feature1
この場合origin/feature1
のポインターを前に進めて(fast-forwardして)feature1と
同じコミットを指すようにすることはできないので、エラーが出てしまいます。
おまけ
feature1
を複数人で共有している場合を考えます。
他のメンバーによってorigin/feature1
がアップデートされたとしましょう。(C8の追加)
ここで、このことに気づかずfeature1
を強制プッシュしてしまうと、リモートブランチは上書きされ、C8は消えてしまいます。
C1--C2--C3-------C6--C7--C4'--C5' <- feature1
\
C4--C5--C8 <- origin/feature1
こういったことが起きないように --force-with-lease
というオプションがあります。