Git Push - Force-with-Lease vs. --force

181

Ich versuche den Unterschied zwischen zu verstehen

git push --force

und

git push --force-with-lease

Ich vermute, dass letztere nur dann auf die Fernbedienung pushen, wenn die Fernbedienung keine Commits hat, die der lokale Zweig nicht hat ?

Alexander Mills
quelle
der "lokale Fernverfolgungszweig ". Grundsätzlich bedeutet dies, dass die Fernbedienung so aussehen muss, wie Ihr Kunde sie erwartet. git help pushEs gibt Anwendungsfälle, die den Zweck erläutern (im Grunde genommen, um Sie davon abzuhalten, eine Änderung zu verwerfen, die jemand gerade hochgeschoben hat). Was mir etwas unklar ist, ist die Funktionsweise des Remote-Tracking-Zweigs. Aber vermutlich muss es in der Regel genau so aussehen, wie es beim letzten Mal fetchoder pullohne neue Commits ausgesehen hat .
Zzxyz
4
@zzxyz: Die tatsächliche Implementierung von --force-with-leaseähnelt der von Vergleichs- und Austauschanweisungen auf modernen CPUs: Derjenige , der den Austausch durchführen möchte, liefert den erwarteten Wert und den neuen Wert. Das System, das den Swap durchführt, vergleicht den erwarteten Wert mit dem tatsächlichen aktuellen Wert und führt den Swap genau dann durch, wenn beide gleich sind. Mit git pushist der erwartete Wert der Wert im Namen der Fernverfolgung, z. B. git push --force-with-lease origin Xsendet er Ihren eigenen origin/Xzusammen mit dem neuen gewünschten Wert. originGit sagt dir, ob es den Austausch gemacht hat oder nicht.
Torek
1
Wenn der Git at originden Austausch gemacht hat, sind Sie fertig. Wenn nicht, können Sie ausführen git fetch origin, um den neuen aktuellen Wert abzurufen, Ihre Änderungen bei Bedarf zu überarbeiten und einen weiteren Force-with-Lease-Vergleich und -Tausch auszuführen, um es erneut zu versuchen.
Torek

Antworten:

171

force Überschreibt einen Remote-Zweig mit Ihrem lokalen Zweig.

--force-with-leaseist eine sicherere Option, die keine Arbeit am Remote-Zweig überschreibt, wenn dem Remote-Zweig mehr Commits hinzugefügt wurden (von einem anderen Teammitglied oder Kollegen oder was haben Sie). Es stellt sicher, dass Sie nicht die Arbeit anderer Personen durch gewaltsames Drücken überschreiben.

Ich denke, Ihre allgemeine Vorstellung von dem Befehl ist richtig. Wenn der Remote-Zweig denselben Wert wie der Remote-Zweig auf Ihrem lokalen Computer hat, überschreiben Sie den Remote-Zweig. Wenn es nicht den gleichen Wert hat, zeigt es eine Änderung an, die jemand anderes an der Remote-Verzweigung vorgenommen hat, während Sie an Ihrem Code gearbeitet haben, und überschreibt daher keinen Code. Wenn in Remote zusätzliche Commits vorhanden sind, sind die Werte natürlich nicht dieselben.

Ich denke nur an --force-with-leasedie Option, die ich verwenden möchte, wenn ich sicherstellen möchte, dass ich keinen Teamkollegen-Code überschreibe. Viele Teams in meinem Unternehmen verwenden --force-with-leaseals Standardoption eine Ausfallsicherung. Es ist in den meisten Fällen unnötig, erspart Ihnen jedoch viele Kopfschmerzen, wenn Sie etwas überschreiben, das eine andere Person zur Fernsteuerung beigetragen hat.

Ich bin mir sicher, dass Sie sich die Dokumente angesehen haben, aber hier könnte eine weitere wortreiche Erklärung enthalten sein:

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

Chevybow
quelle
38

Auf der Suche nach einer Antwort aus glaubwürdigen und / oder offiziellen Quellen.

Das von torek in den Kommentaren und in seiner anderen Antwort erwähnte "Vergleichen und Tauschen" wird durch die Quellen von Git selbst weiter veranschaulicht .

Letzterer pusht nur auf die Fernbedienung, wenn die Fernbedienung keine Commits hat, die der lokale Zweig nicht hat?

Diese Funktion wurde in diesem Commit eingeführt (Dez. 2013, Git v1.8.5-rc0).

--force-with-lease schützt alle Remote-Refs, die aktualisiert werden sollen, indem verlangt wird, dass ihr aktueller Wert mit einem angemessenen Standard übereinstimmt, sofern nicht anders angegeben;

Derzeit wird "ein vernünftiger Standardwert" vorläufig als " der Wert des Remote-Tracking-Zweigs, den wir für die Referenz der zu aktualisierenden Remote haben " definiert, und es ist ein Fehler, wenn wir keinen solchen Remote-Tracking-Zweig haben.

"Leasing" bedeutet also:

" force-with-lease": Sie gehen davon aus, dass Sie den Leasingvertrag für den Schiedsrichter abgeschlossen haben, als Sie abgerufen haben, um zu entscheiden, wie der neu basierte Verlauf aussehen soll, und Sie können nur zurückschieben, wenn der Leasingvertrag nicht gebrochen wurde.

Die Quellen erwähnen immer noch "cas":

  • Diese Option hieß ursprünglich " cas" (für "Vergleichen und Tauschen"), der Name, den niemand mochte, weil er zu technisch war.
  • Der zweite Versuch nannte es "lockref" (weil es konzeptionell dem Drücken nach dem Aufnehmen einer Sperre gleicht), aber das Wort "lock" wurde gehasst, weil es implizierte, dass es das Drücken durch andere ablehnen könnte, was bei dieser Option nicht der Fall ist.
  • Diese Runde nennt es "Force-with-Lease".
    Sie gehen davon aus, dass Sie den Leasingvertrag für den Schiedsrichter abgeschlossen haben, als Sie abgerufen haben, um zu entscheiden, wie der neu basierte Verlauf aussehen soll, und Sie können ihn nur zurückschieben, wenn der Leasingvertrag nicht gebrochen wurde.

Also: " git push --force-with-leasevs. --force"

Wie ich in " push --force-with-leaseStandard " erwähnt habe, kann in Git 2.13 (Q2 2017) erwähnt werden, dass die Option ignoriert werden --force-with-leasekann, wenn ein Hintergrundprozess (wie in einer IDE mit einem Git-Plugin) ausgeführt wird . In diesem Fall herrscht.git fetch origin
--force

VonC
quelle
29

git push --force ist destruktiv, da es das Remote-Repository bedingungslos mit dem überschreibt, was lokal vorhanden ist. Von gits push --force wird dringend abgeraten, da andere Commits zerstört werden können, die bereits in ein freigegebenes Repository übertragen wurden. Eine der häufigsten Ursachen für Force Pushs ist, wenn wir gezwungen sind, einen Zweig neu zu gründen.

Beispielsweise. Wir haben ein Projekt mit einem Feature-Zweig, an dem sowohl Alice als auch Bob arbeiten werden. Beide klonen dieses Repository und beginnen mit der Arbeit. Alice vervollständigt zunächst ihren Teil der Funktion und schiebt ihn in das Haupt-Repository. Das ist alles schön und gut. Bob beendet auch seine Arbeit, aber bevor er sie hochschiebt, bemerkt er, dass einige Änderungen in Master zusammengeführt wurden. Um einen sauberen Baum zu erhalten, führt er eine Rebase gegen den Hauptzweig durch. Wenn er diesen neu basierten Zweig pusht, wird er natürlich abgelehnt. Da er jedoch nicht merkt, dass Alice ihre Arbeit bereits vorangetrieben hat, führt er eine Push-Force durch. Leider werden dadurch alle Aufzeichnungen von Alices Änderungen im zentralen Repository gelöscht.

Was --force-with-lease tut, ist, die Aktualisierung eines Zweigs zu verweigern, es sei denn, dies ist der von uns erwartete Status. dh niemand hat den Zweig stromaufwärts aktualisiert. In der Praxis funktioniert dies, indem überprüft wird, ob der Upstream-Ref das ist, was wir erwarten, da Refs Hashes sind und die Kette der Eltern implizit in ihren Wert kodieren.

Hier ist ein guter Beitrag zu Git Push - Force und Git Push - Force-with-Lease.

Shakil
quelle
2
Was ich nicht verstehe - wenn Sie mit dem Master zurückgreifen, sollten Sie in der Lage sein, ohne zu pushen --force-with-lease? Warum ist --force-with-leasenach dem erneuten Basieren mit dem Master notwendig?
Alexander Mills
3
@AlexanderMills gibt es möglicherweise Möglichkeiten, die Probleme verursachen. Wenn Sie die letzte Person sind, die dies zum Meistern drängt, ist dies kein Problem, aber es gibt eine andere Person, die mit einer anderen Aufgabe arbeitet. Dies kann zu ernsthaften Problemen führen. Sagen Sie zuerst, dass A - B - C im Meister war. Zuerst macht Alice es A - B - C - D - E und gleichzeitig macht Bob es A - B - C - F - G. Wenn Alice die letzte Person ist, drücken Sie im Master nach dem erneuten Basieren von A - B - C - D - E - F - G wird kein Problem verursachen, aber eine andere Person, die Tom versucht, A - B - C - D - E - R gleichzeitig in der Master-Katastrophe zu drücken, wird passieren !! !
Shakil
3
--forceverliert keine Commits, es löst sie nur. Sie können durch ihre Hashes wie in git checkout <SHA>oder wiederbelebt werden git reset --hard <SHA>, vorausgesetzt, der Betreuer des Remote-Repos führt keine GC- oder Schnittvorgänge durch.
Keith Russell
1
"gits push --force wird dringend davon abgeraten, da es andere Commits zerstören kann, die bereits in ein gemeinsam genutztes Repository verschoben wurden." Diese Aussage basiert stark auf Meinungen. Das Ausführen eines Force-Pushs ist Teil eines normalen Workflows zur Überprüfung des Git-Rebase-Codes. Wie bereits erwähnt, können Sie die Commits auch danach abrufen.
Étienne
9

Angenommen, alle Pre-Receive-Hooks auf dem Server akzeptieren den Push, ist dies immer erfolgreich:

git push --force

Während dies eine spezifische clientseitige Prüfung durchführt, bevor Sie fortfahren:

git push --force-with-lease

Sie können die spezifische Prüfung selbst manuell durchführen. Hier ist der "Lease-Checking" -Algorithmus:

  1. Finden Sie Ihren aktuellen Zweig heraus.

  2. Ausführen git for-each-ref refs/remotes. Notieren Sie sich die Commit-ID, die Ihrer Meinung nach dem Upstream-Status Ihres aktuellen Zweigs entspricht.

Wenn Sie sich beispielsweise in der Verzweigung "foo" befinden, notieren Sie sich die Commit-ID, die mit "refs / remotes / origin / foo" verknüpft ist.

  1. Bestimmen Sie jetzt die tatsächliche Commit-ID des Remote-Zweigs auf dem Upstream-Git-Server.

  2. Lassen Sie den "Git Push" nur fortfahren, wenn die aus Schritt 2 und Schritt 3 extrahierten Commit-IDs übereinstimmen. Mit anderen Worten, fahren Sie nur fort, wenn die Vorstellung Ihres lokalen Git-Klons von Upstream mit der tatsächlichen Upstream-Vorstellung übereinstimmt.

Hier gibt es eine traurige Folgerung: Da git fetchalle Refs unter "refs / remotes / origin / *" auf ihre neuesten Versionen aktualisiert werden, ist diese Befehlskombination im Wesentlichen identisch mit 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

Um diese inhärente Schwäche zu git push --force-with-leaseumgehen, versuche ich niemals zu rennen git fetch. Stattdessen führe ich immer dann aus, git pull --rebasewenn ich mit Upstream synchronisieren muss, da git pullnur eine einzige Referenz unter refs / remotes aktualisiert wird, wobei das "Leasing" von --force-with-leaseNutzen bleibt.

G. Sylvie Davies
quelle
1
Wenn die Prüfung clientseitig ist, besteht das Potenzial für eine Rennbedingung? dh jemand anderes drückt Änderungen nach dem Check, aber vor dem erzwungenen Push?
Craq
2

Force-with-Lease ist nicht unbedingt sicher. Es funktioniert einfach so, wie Sylvie es gesagt hat. Ein Hinweis: In git ist ein Zweig nur ein Zeiger auf ein Commit. Und Commits zeigen auf null oder mehr übergeordnete Commits. Selbst wenn Sie den Zweig vollständig mit einem Hard-Git-Reset und einem erzwungenen Push oder einem Push mit - - Force-with-Lease geändert haben, ohne es zu wollen, ist dies nicht unbedingt ein großes Problem. Sie können Ihr lokales Git-Reflog verwenden, um zu sehen, wie sich Ihr lokaler Tipp auf den Zweigen (Wo war HEAD zu diesem Zeitpunkt?) Geändert hat, und den Zweig zurücksetzen und erneut drücken. Dann verlieren Sie nur neue Commits im Remote-Zweig, aber selbst diese können von den Teammitgliedern wiederhergestellt werden.

Fisch
quelle