git push コマンドの -f オプションと + サインの違い
どちらもプッシュ時にファストフォワードじゃなくても, 中断させずに強制的にプッシュするようにするためのものですが, 一体どのような違いがあるのでしょうか?
-f オプションと + サインの同じ使われ方
まず git push でローカルの master ブランチをリモート (origin) の master ブランチにプッシュしたとします:
git push origin master
そしてファストフォワードじゃないというエラーが表示されてそのプッシュが中断されたとします:
! [rejected] master -> master (non-fast-forward)
そんな時に -f (--force) オプションを加えるか, もしくは + サインを <refspec> である master の接頭辞として付加すると, 例えファストフォワードなプッシュにならなくても強制的にプッシュすることでできます. (他のコントリビュータがいない場合や, 限られた状況でのみの使用するべきとされている)
-f オプションを使った場合:
git push -f origin master
+ サインを使った場合:
git push origin +master
このように git push でプッシュする場合, -f オプションもしくは + サインを使っても違いはありません.
ではどのような違いがあるのでしょうか?
-f オプションと + サインの異なる使われ方
-f オプションの場合, プッシュする全てのブランチが一括で強制的にプッシュされます.
一方の + サインはプッシュするブランチ毎に普通にプッシュするのか, それても強制的にプッシュするのかを指定することができます.
つまりは複数のブランチをプッシュする時にのみ, それぞれの違いが出てきます.
次の構文のように git push でプッシュできるブランチは 1 つだけと制限されていませんので:
git push <repository> <refspec>...
<refspec>... が複数のブランチを指定できるという意味になります.
例えば次のような git push で master と feature ブランチを一括で強制的にプッシュする場合, -f オプションを使うことができます:
git push -f origin master feature
それとも master ブランチは普通にプッシュするけれども feature ブランチは強制的にプッシュするという場合, + サインを使うことができます:
git push origin master +feature
反対に master ブランチは強制的にプッシュするけれども, feature ブランチは普通にプッシュするという場合, 次のようになります:
git push origin +master feature
このように複数のブランチをプッシュする際に一括で全てのブランチを強制的にプッシュする場合は -f オプションを使い, 特定のブランチだけ強制的にプッシュする場合は + サインを使うというように使い分けることができます.
もちろん, 最初の例のコマンドは + サインを使って同じように master と feature ブランチを一括で強制的にプッシュすることもできますが, -f オプションに比べてほんの少しだけ冗長になります:
git push origin +master +feature
まとめ
git push で複数のブランチをプッシュする際, まとめて全て強制的にプッシュする場合は, -f オプションを使い, 特定のブランチだけ強制的にプッシュする場合は + サインを使います.
ちなみに <refspec> に : を指定して次のようにすると, リモートレポジトリの名前と一致する全てのローカルレポジトリをリモート (origin) にプッシュできます:
git push origin :
なので, : に + サインを頭に付けて +: とすると, その上記コマンドの強制プッシュ版となります:
git push origin +:
なので -f と + 両者の根本的な違いというのは, 前者はオプションとして使われ, 後者は <refspec> のフォーマットの一部として使われるということになるかと思います.
-f オプションのより詳しい内容は次のリンクより参照できます:
https://git-scm.com/docs/git-push#git-push–f
+ サインのより詳しい内容は, 次のリンクより参照できます:
https://git-scm.com/docs/git-push#git-push-ltrefspecgt82308203
関連記事
Git の 3-way マージで共通祖先が 2 つの場合, 共通祖先はどんな感じになるのか調べてみた2018.08.22
Git の merge.conflictStyle を merge から diff3 に変更したら, マージコンフリクトがより解決しやすくなった2018.08.19
Git の Fetch コマンドの使い方2018.06.07
Git の 'detached HEAD' 状態とその注意点2018.05.31
Git のマージコンフリクトを解決する方法2018.06.13