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 pushmasterfeature ブランチを一括で強制的にプッシュする場合, -f オプションを使うことができます:

git push -f origin master feature

それとも master ブランチは普通にプッシュするけれども feature ブランチは強制的にプッシュするという場合, + サインを使うことができます:

git push origin master +feature

反対に master ブランチは強制的にプッシュするけれども, feature ブランチは普通にプッシュするという場合, 次のようになります:

git push origin +master feature

このように複数のブランチをプッシュする際に一括で全てのブランチを強制的にプッシュする場合は -f オプションを使い, 特定のブランチだけ強制的にプッシュする場合は + サインを使うというように使い分けることができます.

もちろん, 最初の例のコマンドは + サインを使って同じように masterfeature ブランチを一括で強制的にプッシュすることもできますが, -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