web-dev-qa-db-ja.com

git Push --force-with-lease vs. --force

私はの違いを理解しようとしています

git Push -f

そして

git Push --force-with-lease

私の推測では、後者はリモートにプッシュするだけですリモートにローカルブランチにはないコミットがない場合

質問を表現するより良い方法がある場合、lmk、しかし、うまくいけばそれは明確です。

52
Alexander Mills

forceは、リモートブランチをローカルブランチで上書きします。

--force-with-leaseは、より多くのコミットがリモートブランチに追加された場合(別のチームメンバーまたは同僚またはあなたが持っているもの)にリモートブランチの作業を上書きしない、より安全なオプションです。強制的にプッシュして他の人の作業を上書きしないようにします。

コマンドを取り巻く一般的な考えは正しいと思います。リモートブランチがローカルマシンのリモートブランチと同じ値を持つ場合、リモートを上書きします。同じ値を持っていない場合、コードの作業中に他の人がリモートブランチに加えた変更を示しているため、コードは上書きされません。明らかに、リモートに追加のコミットがある場合、値は同じではありません。

チームメイトのコードを上書きしないようにしたいときに使用するオプションとして、--force-with-leaseを考えています。私の会社の多くのチームは、フェールセーフのデフォルトオプションとして--force-with-leaseを使用しています。ほとんどの状況では不要ですが、他の人がリモートに貢献したものを上書きした場合、多くの頭痛の種を救います。

ドキュメントをご覧になったことは間違いありませんが、ここにはさらに詳細な説明が含まれている場合があります。

https://git-scm.com/docs/git-Push

27
chevybow

git Push --forceは、リモートリポジトリをローカルにあるもので無条件に上書きするため、破壊的です。 gitのPush --forceは、既に共有リポジトリにプッシュされている他のコミットを破棄する可能性があるため、強くお勧めしません。強制プッシュの最も一般的な原因の1つは、ブランチのリベースを強制される場合です。

例えば。アリスとボブの両方が取り組む機能ブランチを持つプロジェクトがあります。彼らは両方ともこのリポジトリのクローンを作成し、作業を開始します。 Aliceは最初に機能の一部を完了し、これをメインリポジトリにプッシュします。これはすべて順調です。ボブも作業を終了しますが、作業を進める前に、いくつかの変更がマスターにマージされていることに気付きました。きれいなツリーを維持するために、彼はmasterブランチに対してリベースを実行します。もちろん、彼がこのリベースされたブランチをプッシュするとき、それは拒否されます。しかし、アリスがすでに彼女の作品をプッシュしていることに気づかずに、彼はプッシュフォースを実行します。残念ながら、これにより、中央リポジトリのAliceの変更のすべての記録が消去されます。

-force-with-leaseが行うことは、期待する状態でない限り、ブランチの更新を拒否することです。つまり、誰も上流のブランチを更新していません。実際には、refはハッシュであり、親のチェーンを暗黙的にその値にエンコードするため、アップストリームrefが期待どおりであることを確認することで機能します。

ここ はgit Push --forceおよびgit Push --force-with-leaseに関する良い投稿です。

14
Shakil

信頼できるソースや公式ソースからの回答を探しています。

torek in the comments and in his other answer で言及されている「比較と交換」は、さらに Gitのソースによって説明されています)自体

後者は、リモートにローカルブランチにはないコミットがない場合にのみリモートにプッシュしますか?

この機能は commit 28f5d17 で導入されました(2013年12月、Git v1.8.5-rc0)

--force-with-leaseは、特に指定がない限り、現在の値を何らかの合理的なデフォルトと同じにすることで、更新されるすべてのリモートrefを保護します。

今のところ、「何らかの合理的なデフォルト」は、「更新されるリモートの参照用のリモート追跡ブランチの値」として暫定的に定義されています。 、そのようなリモート追跡ブランチがない場合はエラーになります。

したがって、「リース」とは次のことを意味します。

force-with-lease」:フェッチしたときにrefのリースを取得して、リベースされた履歴を決定し、リースが壊れていない場合にのみプッシュバックできると仮定します。

ソースはまだ「cas」に言及しています:

  • このオプションは、もともと「cas」(「比較と交換」)と呼ばれていました。
  • 2回目の試行では「lockref」(ロックを取得した後のプッシュに概念的に似ているため)と呼ばれましたが、他の人によるプッシュを拒否する可能性があることを暗示しているため、「lock」という言葉は嫌われていました。
  • このラウンドでは、「強制リース」と呼ばれます。
    フェッチしたときにrefのリースを取得して、リベースされた履歴を決定し、リースが壊れていない場合にのみプッシュバックできると仮定します。

だから:「git Push --force-with-lease vs. --force

Push --force-with-leaseデフォルトで 」で述べたように、Git 2.13(2017年第2四半期)が述べているように、オプション--force-with-leaseignoredバックグラウンドプロセス(GitプラグインでIDEにあるようなプロセス)がgit fetch Originを実行する場合。
その場合、--forceが優先されます。

13
VonC

サーバー上の事前受信フックがプッシュを受け入れると仮定すると、これは常に成功します。

git Push --force

これは、先に進む前に特定のクライアント側のチェックを実行します:

git Push --force-with-lease

手動で特定のチェックを実行できます。 「リースチェック」アルゴリズムは次のとおりです。

  1. 現在のブランチを把握します。

  2. git for-each-ref refs/remotesを実行します。 gitクライアントが現在のブランチのアップストリーム状態に対応すると考えるcommit-idに注意してください。

たとえば、ブランチ "foo"にいる場合は、 "refs/remotes/Origin/foo"に関連付けられているcommit-idに注意してください。

  1. 今すぐ、アップストリームgitサーバー上のリモートブランチの実際のcommit-idを確認します。

  2. 手順2と手順3から抽出したcommit-idが一致する場合にのみ、「git Push」を続行させます。つまり、ローカルgitクローンのアップストリームの概念が実際のアップストリームと一致する場合にのみ続行します。

ここには悲しい意味があります:git fetchは "refs/remotes/Origin/*"の下のすべてのrefを最新バージョンに更新するため、このコマンドの組み合わせはgit Push --forceと本質的に同じです:

git fetch

# The command below behaves identically to "git Push --force"
# if a "git fetch" just happened!

git Push --force-with-lease

git Push --force-with-leaseのこの固有の弱点を回避するために、git fetchを実行しないようにします。代わりに、git pull --rebaseはrefs/remotesの下の単一のrefのみを更新し、git pullの "リース"を便利に保つため、アップストリームと同期する必要があるときは常に--force-with-leaseを実行します。

4

強制リースは必ずしも安全ではありません。シルビーが言ったように機能します。注:gitでは、ブランチは単なるコミットのポインターです。また、コミットは、ゼロ以上の親コミットを指します。ハードgitリセットと強制プッシュまたは強制的にプッシュを使用してブランチを完全に変更した場合でも、-force-with-leaseを必要とせずに、それは必ずしも大きな問題ではありません。ローカルgit reflogを使用して、ブランチのローカルヒント(その時点でHEADはどこにあったのか)を確認し、リセットして、ブランチをもう一度プッシュします。次に、リモートブランチでの新しいコミットのみが失われますが、チームメンバによってそれらがコミットされる場合もあります。

1
Fish