要はリモートブランチを別ブランチを元に rebase したい場合のハナシ。
特定のプラットフォームにだけは少し設定を変えたいだとかの場合、 master ブランチをベースとしてプラットフォーム名でブランチを切ってリモートにあげたりしたい。たとえばこういう状況。
, C origin/ios
A - B origin/master
` D origin/android
B が基本の共通機能の最新の commit で C が iOS 用の設定を含んだバージョン、 D が Android 用の設定を含んだバージョン、という形。
別にプラットフォームに限ったハナシじゃなく、特定顧客向けの設定だとかの管理も同様。
基本機能に変更があった場合
基本機能に手直しを入れたり追加があったりするとそれを ios ブランチや android ブランチにも適用したい。そのときの心情としてはこうなってほしいはずだ。
, C origin/ios
A - B - E origin/master
` D origin/android
普通の git push は通らないが、 --force-with-lease オプションを使えばこれに似たようなことはできる。たとえば origin/ios がローカルの ios ブランチに対応しているとして、以下の操作で実現可能。
git checkout ios
git rebase master
git push --force-with-lease origin ios
--force-with-lease は最後に fetch したあとにメンバーが push した場合に push を失敗させるもの。この代わりに fetch 時間をチェックしない -f / --force を使うとタイミングによってはメンバーの commit をふっ飛ばしてしまうので複数人でいじってる場合は使わないほうがいい。
やっていることはリモートブランチの歴史改変
似たようなこと、といったのは上記の git push --force-with-lease を使った操作だと実際のコミットグラフは以下のように C が C' 、 D が D' になるから。
, C' origin/ios
A - B - E origin/master
` D' origin/android
ダッシュありなしの違いは commit id。ブランチの元になる commit が B から E に変更されるのでそれに引きづられてブランチ側の id も変わる。
そもそも git は push するときにローカルとリモートで共通の祖先を持つかどうかをチェックする。 C の親は B 、 C' の親は E なので前述したように --force-with-lease なしの push は失敗する。だけど --force-with-lease オプションはこのチェックを迂回してリモートを書き換えてしまうらしい。
というわけで、祖先を書き換えてしまう、つまり歴史改変をやっているというわけだ。
コマンド長いよ !
.gitconfig に以下を書いておく。
[alias]
overwrite = push --force-with-lease
これで以下のように使える。
git overwrite origin ios