Git-Historie mit dem Interactive Rebase bereinigen
Das interaktive Rebase ist eines der vielseitigsten Tools von Git. Hier erfährst du, wie du damit Commit-Meldungen korrigierst, Fehler behebst und deine Git-Historie ordentlich hältst.
Was ist das Interactive Rebase?
Das Interactive Rebase, auch bekannt als Git Interactive Rebase, wird oft als das „Schweizer Taschenmesser" von Git bezeichnet, da es vielfältige Tools für unterschiedliche Einsatzmöglichkeiten bietet. Ein zentraler und wichtiger Anwendungsbereich ist das Bereinigen der eigenen lokalen Commit-Historie.
Beachte hierbei das Wort „lokal”: Es sollte ausschließlich verwendet werden, um die persönliche Commit-Historie aufzuräumen, z.B. wenn du einen Feature-Branch in einen Team-Branch integrierst. Es ist hingegen nicht geeignet für Commits, die bereits an ein entferntes Repository gepusht und somit geteilt wurden, da interaktives Rebase die Git-Historie „umschreibt”. Im Folgenden findest du einige Beispiel-Szenarien.
Anmerkung: Zur besseren Visualisierung der Szenarios und Workflows in diesem Beitrag habe ich das "Tower" Git Desktop GUI in einigen der Screenshots verwendet.
Korrektur einer alten Commit-Nachricht mit Git Rebase Interactive
Es ist möglich, dass du nach getaner Arbeit einen Tippfehler in einer älteren Commit-Nachricht entdeckst oder merkst, dass eine wichtige Information in der Beschreibung fehlt. Wäre es der allerletzte Commit, könnte man einfach die Option '--amend' des 'git commit' Befehls nutzen, um die Nachricht zu korrigieren. Bei älteren Commits jedoch ist ein interaktives Rebase notwendig, um Änderungen vorzunehmen.
Hier ein Beispiel für eine fehlerhafte Commit-Nachricht, die du korrigieren möchtest:
Eine fehlerhafte Commit-Meldung, die korrigiert werden muss
Bei jeder interaktiven Rebase-Sitzung mit Git musst du zunächst bestimmen, welchen Teil der Commit-Historie du bearbeiten willst. Um den fehlerhaften Commit aus dem vorherigen Beispiel zu ändern, sollte die Sitzung beim übergeordneten Commit beginnen.
Start der interaktiven Rebase-Sitzung
Du kannst nun den Hash dieses Start-Commits an den interaktiven Befehl Git Rebase weitergeben:
$ git rebase -i 0023cddd
Nun öffnet sich ein Editor-Fenster, in dem eine Liste der ausgewählten Commits zur Bearbeitung angezeigt wird. Dabei kann es überraschend sein, dass die Commits in umgekehrter Reihenfolge aufgelistet sind. Dies liegt daran, dass Git in einer interaktiven Rebase-Sitzung die alten Commits schrittweise erneut anwendet. Aus der Perspektive von Git ist diese umgekehrte Reihenfolge daher korrekt.
Editor-Fenster mit den ausgewählten Commits
Ein wichtiger Hinweis zum Editor-Fenster: Du kannst die Commit-Nachricht nicht direkt in diesem Fenster ändern! Stattdessen verwendest du ein Action Keyword (Aktionsschlüsselwort), um den Commit auszuwählen, den du bearbeiten möchtest. Möchtest du die Nachricht eines Commits ändern, markierst du die entsprechende Zeile mit „reword”. Nachdem du das Editor-Fenster gespeichert und geschlossen hast, öffnet sich ein neues Fenster, in dem die alte Commit-Nachricht angezeigt wird. Hier kannst du nun die gewünschten Änderungen vornehmen.
Durchführung der Commit-Änderungen
Nach erneutem Speichern und Schließen ist die interaktive Rebase-Sitzung abgeschlossen und die alte Commit-Nachricht wurde korrigiert!
Kombinieren mehrerer Commits mit interaktivem Rebase
Ein weiterer Anwendungsfall für das interaktive Rebase ist das Zusammenfassen mehrerer alter Commits zu einem einzigen – mithilfe von Git Rebase Interactive Merge Commits. Obwohl die goldene Regel der Versionskontrolle empfiehlt, eher mehrere kleinere Commits als wenige große zu erstellen, gibt es Situationen, in denen das Zusammenführen sinnvoll ist. Beispielsweise kann es vorkommen, dass du rückblickend feststellst, dass ein Commit effektiver ist als mehrere.
Kombinieren von mehrerer Commits zu einem
Wie im ersten Fall beginnt die interaktive Rebase-Sitzung spätestens beim übergeordneten Commit, das manipuliert werden soll.
$ git rebase -i 2b504bee
Es öffnet sich wieder ein Editor-Fenster, in dem der Teil der Commit-Historie aufgelistet ist, der bearbeitet werden soll:
Linien in der Commit-Historie mit „Squash“ markieren
Das hier verwendete Action Keyword heißt „squash“. Um es zu verwenden, musst du noch etwas über „squash“ wissen: Die Zeile, die wir mit dem Schlüsselwort „squash“ markieren, wird mit der Zeile direkt darüber kombiniert. Deshalb wurde, wie im Screenshot zu sehen, die Zeile Nr. 2 mit „squash“ markiert, um sie mit der Zeile Nr. 1 zu kombinieren.
Jetzt kannst du das Editor-Fenster speichern und schließen. Danach erscheint ein neues Fenster, in dem du aufgefordert wirst, eine Commit-Nachricht für den neuen Commit einzugeben, der durch die Kombination der beiden alten Commits erzeugt wird. So entstehen neue Git Interactive Rebase Merge Commits.
Eingabe einer neuen Nachricht für den „squash“-Commit
Nach dem Speichern und Schließen dieses Editor-Fensters siehst du, dass ein neuer Commit erstellt wurde, der die Change-Sets (Änderungssätze) der beiden alten Commits enthält.
Behebung eines Fehlers mit Interactive Rebase
Ein weiteres Einsatzgebiet für das interaktive Rebase ist die Korrektur eines Fehlers in einer früheren Übertragung. Es spielt keine Rolle, welche Art von Fehler gemacht wurde: Vielleicht wurde eine wichtige Änderung vergessen, eine Datei hätte gelöscht werden sollen oder es wurde einfach ein Tippfehler gemacht.
In solchen Fällen könnte die erste Reaktion sein, einfach einen neuen Commit zu erstellen, der den Fehler behebt. Dies kann jedoch die Commit-Historie unübersichtlich machen. Ständig einen ursprünglichen Commit zu erstellen und dann einen weiteren, nur um kleine Fehler zu korrigieren, kann zu einer chaotischen und schwer nachvollziehbaren Commit-Historie führen.
An dieser Stelle kommt „fixup", eines der Tools, die mit interaktivem Rebase geliefert werden, zum Einsatz. Git Rebase Interactive Fixup nimmt diesen „Quick-Fix"-Commit, wendet seine Änderungen auf den ursprünglichen Commit an, korrigiert ihn und entfernt dann den korrigierenden Commit (Band-Aid-Commit):
So funktioniert "fixup"
Nach der Korrektur scheint es, als ob es nie ein Problem mit dem ursprünglichen Commit gegeben hätte. Hier ist ein weiteres praktisches Beispiel für diesen Prozess.
Zunächst solltest du alles tun, was nötig ist, um das Problem zu beheben: Das kann das Hinzufügen einer neuen Datei, das Ändern bestehender Dateien oder das Löschen veralteter Dateien sein. Der nächste Schritt ist, diese Änderungen an das Repository zu senden.
Hierbei nutzt du beim Commit die Option '--fixup' und gibst den Commit-Hash des fehlerhaften Commits an, um Git deutlich zu machen, welcher ursprüngliche Commit korrigiert werden soll.
$ git add corrections.txt
$ git commit --fixup 2b504bee
Wenn du dir nun die Commit-Historie anschaust, wirst du feststellen, dass ein recht gewöhnlich aussehender Commit erstellt wurde, der zunächst einmal wenig spektakulär scheint. Bei genauerer Betrachtung aber wirst du bemerken, dass doch etwas Unerwartetes passiert ist: Dem neuen Commit wurde automatisch „fixup!“ gefolgt vom Betreff des fehlerhaften Commits vorangestellt – pure Magie!
Die ursprüngliche Übertragung und die Korrekturübertragung
Der dritte – wieder etwas gewöhnlichere – Schritt besteht nun darin, die interaktive Rebase-Sitzung zu starten. Auch hier wählst du den Parent der fehlerhaften Übertragung als Startpunkt:
$ git rebase -i 0023cddd --autosquash
Als Nächstes verwendest du die Option '--autosquash'. Diese Option sorgt dafür, dass du in dem nun geöffneten Editor-Fenster selbst nichts ausführen musst.Wir schauen uns das mal genau an:
Der Fix-Commit wird als „fixup" markiert und an die richtige Position sortiert
Git hat automatisch zwei Dinge gemacht:
- Es hat den zu korrigierenden Commit als „fixup" markiert.
- Es hat die Zeilen neu sortiert, sodass der zu korrigierende Commit direkt unter dem fehlerhaften Commit erscheint. Das liegt daran, dass „fixup“ genau wie „squash“ funktioniert, indem es mit der darüber liegenden Zeile kombiniert wird.
Nun speicherst du das Editor-Fenster und schließt es dann.
Der Commit-Verlauf sieht nun so aus:
Ein Happy End!
Nun sind nicht nur die Korrekturen aus dem „Band-Aid-Commit“ in den ursprünglich fehlerhaften Commit integriert worden, sondern der fehlerhafte Commit ist auch aus der Commit-Historie verschwunden. Alles ist nun so bereinigt, dass es scheint, als hätte es nie ein Problem gegeben.
Entdecke die Leistungsfähigkeit von Git Rebase Interactive
Wie du gesehen hast, gibt es für interaktives Rebase viele Einsatzmöglichkeiten, vor allem im Bereich der Fehlerbehebung. Für einen Überblick über weitere nützliche Anwendungen ist das kostenlose "First Aid Kit for Git" empfehlenswert. Diese Sammlung besteht aus kurzen Videos (2-3 Minuten pro Episode), die dir zeigen, wie du Fehler mit interaktivem Rebase und anderen Git-Tools rückgängig machen kannst.
Weitere Git-Tipps und -Tricks
- 15 Git tips to improve your workflow (englischsprachiger Artikel)
- How Git Partial Clone lets you fetch only the large file you need (englischsprachiger Artikel)
- Git happens! 6 Common Git mistakes and how to fix them (englischsprachiger Artikel)
Über den Gastautor
Tobias Günther ist der CEO von Tower, der beliebten Git-Desktopanwendung, welche bereits über 100.000 Entwicklerinnen und Entwickler dabei geholfen hat, noch produktiver zu werden.
Coverbild von David Taljat bei Pexels