Was ist der Unterschied zwischen git cherry-pick und git format-patch | git bin?

Lesezeit: 7 Minuten

Was ist der Unterschied zwischen git cherry pick und git format patch
Felix Dombek

Manchmal muss ich ein Tag mit einem bestimmten Fix in meinem Zweig herauspicken, was ich früher über gemacht habe

git cherry-pick tags/myfix

Dies funktioniert, aber das Rosinenpicken dauert immer länger, um “ungenaue Umbenennungserkennung” durchzuführen.

Meine Vermutung war, dass es damit schneller gehen könnte

git format-patch -k -1 --stdout tags/myfix | git am -3 -k

Tatsächlich stellte sich heraus, dass dies den Fix sofort anwendete und meinen Zweig in genau demselben Zustand wie beim Rosinenpicken zurückließ.

Jetzt ist meine Frage, was genau macht Cherry-Picking anders? Ich dachte, Cherry-Picking wäre im Grunde genau so implementiert, aber ich muss mich geirrt haben.

  • Nicht -X no-renames schalte das ab?

    – o11c

    31. August 18 um 17:51 Uhr

  • @o11c – Ja, das sollte es. Ich mache es mir nicht zur Gewohnheit, das zu verwenden, da es das Zusammenführungsergebnis stillschweigend durcheinander bringen könnte, aber in Fällen, in denen Sie wissen, dass es sicher ist, würde es die Zeitsenke vermeiden.

    – Markus Adelsberger

    31. August 18 um 18:31 Uhr

Was ist der Unterschied zwischen git cherry pick und git format patch
Markus Adelsberger

cherry-pick wird als Merge implementiert, wobei die Merge-Basis das übergeordnete Element des Commits ist, das Sie einbringen. In Fällen, in denen es keine Merge-Konflikte gibt, sollte dies genau den gleichen Effekt haben wie das Generieren und Anwenden des Patches, wie Sie es getan haben (aber siehe Toreks Antwort für eine kleine Einschränkung, wo am könnte theoretisch das Falsche tun).

Aber durch eine Zusammenführung cherry-pick kann versuchen, Fälle, in denen Änderungen vorgenommen werden, eleganter zu handhaben möchten Konflikt. (Tatsächlich ist die -3 Option, die Sie gegeben haben am sagt ihm, dass es bei Bedarf dasselbe tun sollte, wenn es genug Kontext im Patch hat, um dies tun zu können. Ich komme darauf am Ende zurück…)

Wenn Sie einen Patch anwenden, schlägt die Anwendung standardmäßig fehl, wenn er einen Codeblock ändert, der in dem Commit, in dem Sie ihn anwenden, nicht derselbe ist wie in dem übergeordneten Commit, aus dem er generiert wurde. Aber die cherry-pickDer /merge-Ansatz untersucht, was diese Unterschiede sind, und erzeugt daraus einen Merge-Konflikt – so haben Sie die Möglichkeit, den Konflikt zu lösen und fortzufahren.

Im Rahmen der Konflikterkennung cherry-pick benennt Erkennung um. Sagen Sie zum Beispiel, Sie haben

o -- x -- x -- A <--(master)
      
       B -- C -- D <--(feature)

Und Sie cherry-pick verpflichten C auf zu master. Angenommen bei o Sie erstellt file.txtund in A Sie haben Änderungen an file.txt. Aber verpflichte dich B bewegt file.txt zu my-old-file.txtund begehen C modifiziert my-old-file.txt.

Der Wechsel zu my-old-file.txt in C könnte mit der Änderung in Konflikt stehen file.txt in A; aber um diese Möglichkeit zu sehen, muss Git eine Umbenennungserkennung durchführen, damit es das herausfinden kann file.txt und my-old-file.txt sind “das Gleiche”.

Sie wissen vielleicht, dass Sie diese Situation nicht haben, aber Git weiß es nicht, bis es versucht, Umbenennungen zu erkennen. Ich bin mir nicht sicher, warum das in diesem Fall zeitaufwändig wäre; Meiner Erfahrung nach ist dies normalerweise nicht der Fall, aber in einem Repo mit vielen hinzugefügten und gelöschten Pfaden (zwischen B und entweder C oder A in unserem Beispiel) könnte es sein.

Wenn Sie stattdessen einen Patch generieren und anwenden, wird es versucht um den Patch unter der Annahme anzuwenden, dass kein Konflikt besteht. Nur wenn dies auf ein Problem stößt (und dann nur, weil Sie die -3 Option) wird es auf eine Zusammenführung mit Konflikterkennung zurückgreifen. All das – und jede potenzielle Umbenennungserkennung – kann übersprungen werden, solange der erste Versuch sauber angewendet wird.


Aktualisieren – Wie in den Kommentaren zu der Frage erwähnt, können Sie die Umbenennungserkennung auch deaktivieren, wenn sie nicht hilft und langsam läuft. Wenn Sie dies verwenden, wenn es tatsächlich Umbenennungen gibt, die für die Zusammenführung “wichtig” sind, kann dies Konflikte verursachen, bei denen die Umbenennungserkennung sie lösen würde. Obwohl ich nicht denke, dass es das sollte, kann ich nicht ausschließen, dass es auch nur ein falsches Zusammenführungsergebnis berechnet und es stillschweigend anwendet – weshalb ich diese Option selten verwende.

Für die standardmäßige Zusammenführungsstrategie ist die -X no-renames Option schaltet die Umbenennungserkennung aus. Sie können diese Option an übergeben cherry-pick.

Laut Toreks Kommentar scheint die Umbenennungserkennung kein Problem zu sein am. Allerdings kann ich bestätigen, dass es in der Lage ist, einen Fall richtig zu handhaben, in dem das Zusammenführen nur mit der Umbenennungserkennung funktioniert. Irgendwann, wenn nicht Freitagnachmittag ist, werde ich versuchen, die Einzelheiten zu verstehen.

  • Wann git am auf Drei-Wege-Merge zurückgreift, ist es zu spät: Es gibt keine Chance für eine Umbenennungserkennung. Git hat die Dateiidentifikation bereits durchgeführt! (Der am Code verwendet die Blob-Hashes in der index Linien, wie in zu sehen git diff Ausgang. An dieser Stelle sind keine Dateinamen mehr vorhanden.)

    – Torek

    31. August 18 um 18:39 Uhr


  • @torek Hmm …. An einem Freitag ist es für mich zu spät, um mich ganz darauf einzulassen, aber ich nehme Ihr Wort dafür und aktualisiere es entsprechend. Ich werde versuchen, es später vollständig zu verstehen 🙂

    – Markus Adelsberger

    31. August 18 um 19:42 Uhr

Die Antwort von Mark Adelsberger ist richtig (und positiv bewertet, und wahrscheinlich sollten Sie sie akzeptieren). Aber es gibt hier eine historische Kuriosität zu beachten.

Tatsächlich wurde Cherry-Pick einmal implementiert wie git format-patch | git am -3und git rebase verwendet immer noch diese spezielle Methode zum Kopieren von Commits für einige Arten von Rebase.1 Das Problem hier ist, dass dies umbenannte Dateien nicht erkennt und manchmal – unter (seltenen) Bedingungen, die schwer zu beschreiben sind, aber ich werde es versuchen – Änderungen falsch anwendet, wo eine ordnungsgemäße Drei-Wege-Zusammenführung sie korrekt anwenden würde. Betrachten Sie zum Beispiel diesen Fall:

@@ -123,5 ... @@
     }
   }
-  thing();
   {
     {

wo der umgebende Kontext um eine gelöschte Zeile nur Klammern (oder noch schlimmer, Leerzeichen) sind – mit anderen Worten etwas, das nutzlos passt. In deine Version derselben Datei, aufgrund eines anderen Ereignisses, was war Die Zeilen 123 bis 127 befinden sich jetzt früher oder später in derselben Datei. Sagen wir zum Beispiel, dass es jetzt die Zeilen 153-158 sind. Inzwischen Zeilen 123-127 in deine gelesene Datei:

    }
  }
  thing();
  {
    {

aber diese Zeilen sind korrekt: der Aufruf an thing() das sollte gelöscht werden (weil es falsch ist) ist nach unten verschoben, aber es gibt einen Aufruf dazu thing() das sollte nicht gelöscht werden, an derselben Stelle.

Eine Drei-Wege-Zusammenführung vergleicht die Zusammenführungsbasis mit ihr deine Version, und vielleicht—könnte seinje nach Glück und unterschiedlichem Kontext – stellen Sie fest, dass Sie verschiedene Zeilen eingefügt haben, sodass der fehlerhafte Anruf, der gelöscht werden sollte, jetzt in Zeile 155 und nicht in Zeile 125 steht. Er wird dann die korrekte Löschung durchführen, da er weiß, was die Basis war Zeile 125 ist deine Zeile 155.

Die Umbenennungserkennung ist der wichtigere dieser beiden Unterschiede zwischen Format-Patch-then-Apply und echtem Drei-Wege-Merge, aber in einigen Fällen spielen beide eine Rolle. Betrieb git cherry-pick macht das Gründlichere, langsamere, öfter Korrektere.


1Insbesondere nur die nicht-interaktiven git rebase jemals format-patch verwendet, und selbst dann nur, wenn Sie nicht benutze die -m Option, geben Sie eine Zusammenführungsstrategie mit an -soder geben Sie eine erweiterte Option mit an -X. Jede dieser drei erzwingt die nicht-interaktive Rebase, die Cherry-Pick-Methode zu verwenden.

Beachten Sie, dass die Git-Dokumentation die -X Argumente “Strategieoptionsoptionen” oder “Strategieoptionsargumente”, was so oder so ein sehr ungeschickter Ausdruck ist. Ich mag das Wort “erweitert” hier, da es erklärt, warum es so ist -X, dh erweitert. Eine erweiterte Option ist einfach eine bestandene Option zu die Strategie, mit der Sie sich entscheiden -s: Git weiß nicht, welche zusätzlichen Optionen jeder hat -s versteht, also was auch immer Sie geben -Xgibt Git der gewählten Strategie nach, und die Strategie selbst akzeptiert dann entweder die -X Option und tut etwas oder beschwert sich darüber als unbekannt.

.

640140cookie-checkWas ist der Unterschied zwischen git cherry-pick und git format-patch | git bin?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy