Warum zeigt Git Rebase keine Commits an, die ich quetschen möchte?

Lesezeit: 7 Minuten

Benutzer-Avatar
Brosef

Ich bereite mich darauf vor, eine Pull-Anforderung für einen Zweig zu initiieren, an dem ich arbeite. Auf Github sehe ich, dass ich 5 Commits vor dem Master bin, also würde ich meine Commits gerne in einen quetschen. Ich führe ein Git-Protokoll aus, um zu sehen, was die vorherigen Commits sind:

git log --oneline

4363273 Updated Order_Entry with bulk UPDATE command
e7e0c64 Updated Order Entry module and Orders Schema
2cff23e Merge branch 'order_schema'
104b2ce Orders Schema
f7d57cf Order Entry updated to handle and log responses from LC
afa1b7b Merge pull request #18 from project/bugfix/mockvenue
4b2c8d8 Return correct string in mock venue API

Jetzt denke ich, dass ich die oben aufgeführten Top-5-Commits (4363273-f7d57cf) quetschen möchte. Also führe ich dann aus:

git rebase -i HEAD~5

4363273 Updated Order_Entry with bulk UPDATE command
pick 44768b2 Add script to run simulation on a strategy
pick f82ec8d Implement mock venue
pick f7d57cf Order Entry updated to handle and log responses from LC
pick 4b2c8d8 Return correct string in mock venue API
pick 104b2ce Orders Schema
pick 4363273 Updated Order_Entry with bulk UPDATE command

Wie kommt es, dass die Liste der Commits, die nach dem Ausführen von git rebase angezeigt wird, nicht mit den ersten 5 Commits übereinstimmt, wenn ich git log ausführe? Warum erscheinen insbesondere e7e0c64 und 2cff23e im Git-Protokoll, aber nicht im Git-Rebase?

* 4363273 Updated Order_Entry with bulk UPDATE command
*   e7e0c64 Updated Order Entry module and Orders Schema
|\
| *   2cff23e Merge branch 'order_schema'
| |\
| | * 104b2ce Orders Schema
| * |   afa1b7b Merge pull request #18 from project/bugfix/mockvenue
| |\ \
| | "https://stackoverflow.com/" "https://stackoverflow.com/"
| | * 4b2c8d8 Return correct string in mock venue API
| |/
* | f7d57cf Order Entry updated to handle and log responses from LC
|/
*   8ed2260 Merge pull request #17 from project/mockvenue

Geben Sie hier die Bildbeschreibung ein

  • git log sortiert nach Datum (standardmäßig), aber git rebase muss (und tut es daher) topologische Ordnung verwenden. Was passiert, wenn Sie hinzufügen --graph zu deinem git log --oneline? (Verwenden --graph zeigt ein Diagramm von Commits und Forces git log um topologisch zu sortieren.) (Sie könnten auch hinzufügen --decorate die Ihnen Zweignamen und dergleichen anzeigen wird, obwohl dies bei der Verwendung tendenziell interessanter ist --all als wenn Sie es nicht benutzen.)

    – Torek

    26. Februar 2016 um 18:49 Uhr


  • @torek Ich habe die Grafik gepostet. Ich schaue es durch und verstehe immer noch nicht, warum e7e0c64 und 2cff23e nicht angezeigt werden, wenn ich den Rebase-Befehl ausführe.

    – Brosef

    26. Februar 2016 um 19:29 Uhr

Ihr Diagramm zeigt zahlreiche Zusammenführungen. Dies ist die Ursache des Problems. Das ist hier erwähnenswert HEAD~5 bedeutet „fünf Schritte rückwärts folgend --first-parent“.


Lassen Sie uns zuerst ein wenig Hintergrundwissen behandeln. Im Allgemeinen können Sie eine Zusammenführung nicht rebasieren, und Rebase versucht es normalerweise nicht (es verwirft sie normalerweise nur). Verwenden git rebase -p wird versuchen, Zusammenführungen beizubehalten, und wird oft erfolgreich sein, aber es ist sehr schwierig, es interaktiv zu verwenden (weil das Bearbeitungsskript keine Darstellung für Zusammenführungen hat).

Wir können mehr sehen, sobald wir verstehen, wie Rebase funktioniert. Angenommen, wir haben ein Commit-Diagramm wie dieses:

          B - C - D   <-- other-branch
        /
... - A
        \
          E - F - G   <-- your-branch
  1. Rebase nimmt eine Reihe von Commits und wandelt sie in Changesets/Patches um. Das heißt, wenn Sie Commits haben E, Fund G die folgen Commit Agit muss ein diff erzeugen von A zu Edann ab E zu Fund schließlich von F zu G. Diese stellen dar, „wie man vom Basis-Commit konvertiert“ (derzeit A) “bis zur Spitze, als Folge von Modifikationen.”

  2. Dann wendet sich rebase dem neuen Basis-Commit zu, in diesem Fall Commit D, und wendet diese Patches nacheinander an. Der Wechsel von A zu Ewie angewendet auf Dmacht einen neuen Commit E'. Der Wechsel von E zu Fangewendet E'macht einen neuen Commit F'. Die endgültige Änderung wird G'.

Das Ändern eines Commits in einen Patch (durch Vergleichen mit seinem übergeordneten Element) und das anschließende Anwenden des Patches ist buchstäblich a git cherry-pick. Mit anderen Worten, rebase ist nur eine Reihe von Cherry-Pick-Operationen, die Commits auswählen E, Fund G auf einen neuen Zweig, der sich von erstreckt D. Das neue Commit-Diagramm würde wie folgt aussehen:

          B - C - D   <-- other-branch
        /           \
... - A               E' - F' - G'   <-- your-branch
        \
          E - F - G   [reflog only]

Wenn wir dasselbe mit einem Merge-Commit versuchen, stoßen wir auf ein Problem. Eine Zusammenführung hat zwei (oder mehr) Eltern und kann nicht ohne menschliche Hilfe ausgewählt werden: Sie müssen es sagen git cherry-pick welcher Elternteil ist derjenige, gegen den zu differenzieren ist.

Was git rebase -p Wiederholen Sie die Zusammenführung, anstatt eine Rosinenpickerei zu versuchen. Die Rebase-Dokumentation enthält dieses Beispiel, in dem Sie rebasen können A auf zu Q:

                  X
                   \
                A---M---B
               /
       ---o---O---P---Q

Sie zeigen nicht das Ergebnis, aber es sollte so aussehen (idealerweise mit dem Original A--M--B Sequenz ausgegraut):

                  X--------
                   \       \
                A---M---B   "https://stackoverflow.com/"
       ---o---O---P---Q     |
                       \    |
                        A'--M'--B'

Beachten Sie diesen neuen Commit M' muss eine Zusammenführung zwischen sein A' und (unverändert) übergeben X. Dies funktioniert, wenn die Zusammenführung eine normale (nicht “böse”) Zusammenführung ist, ist aber zumindest offensichtlich etwas knifflig.


Kommen wir zurück zu Ihrer speziellen Situation, wo git log --graph hat den Text unten gegeben (den ich nur ein wenig modifiziert habe). Es ist ein bisschen schwierig, sich seitwärts zu drehen (die anderen Grafiken oben haben Vorgänger-Commits auf der linken Seite und Nachfolger auf der rechten Seite, während die git log --graph Ausgabe hat Vorgänger unten und Nachfolger oben), aber ich werde es kurz versuchen, indem ich Einzelbuchstabencodes für jeden Commit hinzufüge:

H   * 4363273 Updated Order_Entry with bulk UPDATE command
G   *   e7e0c64 Updated Order Entry module and Orders Schema
    |\
F   | *   2cff23e Merge branch 'order_schema'
    | |\
E   | | * 104b2ce Orders Schema
D   | * |   afa1b7b Merge pull request #18 from project/bugfix/mockvenue
    | |\ \
    | | "https://stackoverflow.com/" "https://stackoverflow.com/"
C   | | * 4b2c8d8 Return correct string in mock venue API
    | |/
B   * | f7d57cf Order Entry updated to handle and log responses from LC
    |/
A   *   8ed2260 Merge pull request #17 from project/mockvenue

Jetzt mit A als Commit ganz links und H als ganz rechts:

    C---D
   /___/ \
  //__--E-F
 ///       \
A-----B-----G--H

Das Direkte (erster Elternteil) Ahnenlinie geht von H zu Gdann zu Bdann zu A. Das bedeutet, dass HEAD~5 ist ein Commit, das wir nicht einmal sehen können (zwei links von A), und git rebase -i HEAD~5 auflisten sollte alle dieser Commits mit Ausnahme von Merges (D, F und G). Das wären fünf Commits: A, B, C, Eund H. Aber basierend auf seiner Protokollnachricht, A ist auch eine Verschmelzung. Uns fehlen hier Informationen und wir können nicht die vollständige Grafik zeichnen (was auch gut so ist, da die kompakte Form eine viel von Linien darin).

Jedenfalls ist dies tatsächlich der Fall. Das rebase Der Befehl findet Commits für Cherry-Pick, indem er jeden Commit auflistet, der vom Tipp-Commit (HEADwas Commit ist H) das ist nicht erreichbar vom ersten ausgeschlossenen Commit (HEAD~5ein Commit zwei Schritte links davon A, also können wir es nicht sehen). Anschließend wirft es Merge-Commits aus und wählt jedes verbleibende Commit aus, um einen neuen, linearen Zweig zu erstellen.

Ob dies sinnvoll ist und welche Commits Sie aussuchen sollten, kann Ihnen niemand beantworten.

  • Wow. Danke für diese Erklärung. Hat mir wirklich etwas Klarheit gebracht. Ich dachte, ich hätte Rebase verstanden, aber es steckt eindeutig noch viel mehr dahinter. In meinem Diagramm, das Sie alphabetisch geordnet haben, erscheinen die Commits A, D, F und G nicht, wenn ich Rebase ausführe, weil sie alle Merge-Commits sind?

    – Brosef

    27. Februar 2016 um 2:02 Uhr

  • Ja (Entschuldigung für die verspätete Antwort, ich war auf einem Wochenendausflug).

    – Torek

    29. Februar 2016 um 2:16 Uhr

  • Was für eine Antwort. Perfekt erklärt. Vielen Dank, dass Sie so hilfreich sind.

    – denik1981

    26. Mai 2021 um 4:27 Uhr

1093220cookie-checkWarum zeigt Git Rebase keine Commits an, die ich quetschen möchte?

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

Privacy policy