Git leicht gemacht: Verlauf mit Rebase ändern – Teil II
Or Kamara
17. Juni 2020
0 Min. LesezeitWillkommen zurück zum zweiten Teil unserer Anleitung für die einfache Arbeit mit Git!
Im vorherigen Artikel haben wir die Grundlagen von Rebase sowie zwei häufige Szenarien besprochen, denen wir alle bei der Arbeit mit Git begegnen können. Den ersten Teil finden Sie hier. In diesem Teil sehen wir uns vier weitere häufige Szenarien und einige abschließende Erkenntnisse an.
Legen wir gleich los!
Häufige Szenarien (und wie Sie damit umgehen!) – Teil II
Setzen wir dort fort, wo wir beim letzten Mal aufgehört haben: mit einigen häufigen Szenarien, in denen Sie den Verlauf Ihres Codes ändern möchten, und damit, wie Sie das mit Git erledigen:
1. Einen älteren Commit in zwei aufteilen (edit)
Angenommen, Sie haben gerade bemerkt, dass Ihnen beim Zusammenführen von zwei Commits ein Fehler unterlaufen ist (weitere Informationen finden Sie in Teil I) und Sie möchten den Squash von 17a73c1 in e2952e7 rückgängig machen, damit die neue Datei in einem anderen Commit landet. Führen Sie dazu alle Commits bis zu dem Punkt aus, den Sie bearbeiten möchten, halten Sie an, nehmen Sie die Änderungen vor und fahren Sie fort. Anders gesagt: Verwenden Sie die Option edit.
Wir führen erneut git rebase -i master aus, diesmal jedoch mit der Option edit für den Commit, den wir aufteilen möchten (den zweiten Commit, `6871683`):
Nachdem Sie die Rebase-Ansicht geschlossen haben, sollte Folgendes angezeigt werden:
Git hat also im Grunde den ersten und zweiten Commit ausgeführt und angehalten. Jetzt sind wir am Zug und können alle gewünschten Änderungen vornehmen!
So sieht unser Git-Graph derzeit aus:
Wie bereits erwähnt, möchten wir den zweiten Commit im Grunde in zwei separate Commits aufteilen, einen pro Datei. Als ersten Schritt setzen wir die Änderungen des zweiten Commits mit git reset --soft HEAD^ zurück. Der Befehl reset ändert den Commit, auf den der Branch-HEAD derzeit verweist. Mit der Option --soft behalten wir den Index und das Arbeitsverzeichnis bei, während alle Dateien, die zwischen dem ursprünglichen HEAD und dem Commit geändert wurden, zum Staging vorgemerkt werden.
Das ist der neue Git-Status. Wie Sie sehen, sind beide Dateien vorgemerkt:
Nehmen wir nun b2.txt mit git restore --staged b2.txt aus der Liste der vorgemerkten Dateien:
Da nur b.txt als Datei vorgemerkt ist, können wir jetzt den ersten Teil des zweiten Commits erstellen. Anschließend nehmen wir b2.txt ins Staging auf und erstellen den zweiten Teil des zweiten Commits:
So sieht unser Git-Graph jetzt aus:
Im letzten Schritt setzen wir den Rebase fort und führen die übrigen Commits aus:
git rebase --continue. Der fertige Git-Graph sollte dann so aussehen:
2. Alle Dateien in einem bestimmten Commit ändern (edit)
Das nächste Szenario kennen Sie wahrscheinlich alle: Sie haben Ihren Code, sauber auf mehrere Commits verteilt, gepusht – und stellen dann fest, dass Sie vergessen haben, den Linter für Ihren Code auszuführen. Wie bereits erläutert, sollte die Lösung nicht in einem weiteren Commit namens fix linting bestehen. Stattdessen sollten Sie das Linting für jeden einzelnen Commit korrigieren.
Bei einer kleinen Änderung können wir die Option squash verwenden. Gibt es jedoch mehrere Änderungen in mehreren Commits, ist es am besten, unser Linting-Skript einzeln für jeden Commit (oder für die Commits, die wir korrigieren möchten) auszuführen. Dafür können wir wieder die Option edit verwenden, wie im vorherigen Beispiel.
Führen wir erneut git commit rebase -i aus und verwenden dabei die Option edit für den ersten Commit (einen Commit mit mehreren Dateien):
Wie zuvor hält Git nach dem Ausführen des ersten Commits an:
Jetzt können wir unseren Linter (z. B. npm run lint) ausführen und den Status unseres Repos prüfen:
Wie Sie sehen, hat das Linting-Skript den Inhalt von sechs Dateien (a*.txt) geändert. Jetzt müssen wir nur noch die aktuellen Änderungen übernehmen (indem wir sie zum Staging hinzufügen und committen) und den Rebase fortsetzen:
Der Git-Graph sollte dann so aussehen:
3. Sicherstellen, dass alle Tests für jeden Commit bestehen (exec)
Wenn Sie Ihren Code auf mehrere Commits aufteilen, sollten Sie daran denken, dass jeder Commit für sich bestehen sollte. Anders gesagt: Nach dem Zusammenführen mehrerer Commits in einen der Haupt-Branches sollten Sie zu jedem einzelnen zurückspringen können und erwarten dürfen, dass sich der Code kompilieren lässt und alle Tests bestehen.
Wie können Sie das vor dem Zusammenführen der Commits überprüfen?
Führen wir unsere Tests für jeden einzelnen Commit manuell aus! Natürlich nur ein Scherz – wir sollten das automatisch erledigen :) Dafür können wir die Option exec verwenden.
Mit dieser Option können wir Shell-Skripte als Teil des Rebase-Prozesses ausführen. Dazu müssen wir nur an den gewünschten Stellen neue Zeilen mit dem exec-Befehl einfügen. Führen wir zum Beispiel erneut git rebase -i master aus:
Jetzt kommt der spannende Teil: Wir führen nach jedem Commit die Tests aus, indem wir das Skript ./run_tests.sh ausführen:
So sieht die Ausgabe aus, wenn Sie die Rebase-Ansicht schließen:
Wie Sie sehen, hat Git das Testskript nach jedem Commit ausgeführt. Jetzt wissen wir also, dass etwas im Commit feat: 2nd commit die Tests fehlschlagen lässt. Sie können auch nach jedem Commit einen einzelnen exec-Befehl hinzufügen, indem Sie Folgendes ausführen:
$ git rebase -i --exec "./run_tests.sh"
Das Letzte (eigentlich Erste), was Sie wissen sollten: So brechen Sie ab
Das ist kein Szenario, sondern eher eine Warnung: Der Rebase-Befehl kann gefährlich sein!Wenn Sie ihn verwenden, ohne die Auswirkungen der Befehle zu verstehen, können Sie Ihre Arbeit ruinieren. Deshalb möchte ich zunächst zwei Empfehlungen geben:
Bevor Sie mit den Commits experimentieren, sollten Sie immer sicherstellen, dass Sie ein geeignetes Backup Ihres Git-Repos haben. Am einfachsten ist es meiner Meinung nach, alle Änderungen in einen Remote-Branch zu pushen. Falls etwas schiefgeht, kann ich jederzeit zu meinem ursprünglichen Code zurückkehren (mit
git reset).Stellen Sie sicher, dass Sie die Befehle verstehen. Testen Sie sie zunächst in einem temporären Git-Repo, statt sie zum ersten Mal auf Ihren tatsächlichen Code anzuwenden.
Denken Sie daran: Sie können den Rebase-Prozess jederzeit anhalten und zum ursprünglichen Zustand zurückkehren:
Löschen Sie auf der ersten Rebase-Seite einfach alle Commit-Zeilen. Dann wird nichts geändert.
Wenn Sie sich mitten im Rebase-Prozess aus irgendeinem Grund nicht mehr zurechtfinden und nicht wissen, was zu tun ist, können Sie jederzeit
git rebase --abortausführen. Dieser Befehl stoppt den Rebase-Prozess und setzt Ihr Repository auf den ursprünglichen Zustand zurück (also auf den Zustand vorgit rebase -i).
Zusammenfassung
Wie wir in den letzten Beispielen gesehen haben, ist git rebase ein leistungsstarker Befehl – insbesondere im interaktiven Modus. Es gibt unzählige Anwendungsfälle, aber ich hoffe, ich konnte Ihnen ein grundlegendes Verständnis dafür vermitteln, wann die einzelnen Optionen hilfreich sind.
Die wichtigste Erkenntnis aus diesem Artikel: Verwenden Sie git rebase clever und mutig. Ich weiß, dass der Einstieg etwas beängstigend sein kann und Sie vielleicht jemanden an Ihrer Seite haben möchten, wenn Sie die Eingabetaste drücken – das ist völlig in Ordnung. Wenn Sie regelmäßig üben, wird es zur Routine. Außerdem gibt es sicher noch viele weitere Szenarien, in denen dieser Befehl für Ihre konkreten Anwendungsfälle nützlich ist.
Viel Spaß!
Starten Sie mit Capture the Flag
Erfahren Sie in unserem virtuellen On-Demand-Workshop für Einsteiger, wie Sie Capture-the-Flag-Herausforderungen lösen.



