Ein Leitfaden zu Git Interactive Rebase, mit praktischen Beispielen

Die Versionskontrolle mit Git ist zu einem Standard in jedem modernen Entwicklerwerkzeugkoffer geworden. Befehle wie commit, push und pull haben es in unsere Finger-Muskelgedächtnis geschafft. Aber verhältnismäßig wenige Entwickler kennen die „fortgeschritteneren“ Funktionen in Git – und wie unglaublich wertvoll sie sein können! In diesem Artikel werden wir „interaktiven Rebase“ erkunden, einer der mächtigsten Werkzeuge in Git.

Warum interaktiver Rebase Teil jedes Entwicklerwerkzeugs sein sollte

Kurz und gut, und ohne Übertreibung, kann interaktiver Rebase Ihnen dabei helfen, ein besserer Entwickler zu werden, indem Sie eine saubere und gut strukturierte Commit-Historie in Ihren Projekten erstellen.

Warum ist eine gut strukturierte Commit-Historie wichtig? Stellen Sie sich das Gegenteil vor: eine schwer zu lesende Commit-Historie, bei der Sie keine Ahnung haben, was Ihre Kollegen tatsächlich mit ihren jüngsten Änderungen gemacht haben. Immer mehr „dunkle Ecken“ beginnen in einem solchen Projekt aufzutauchen, und Sie verstehen nur die kleinen Teile, an denen Sie selbst gearbeitet haben.

Im Gegensatz dazu hilft eine saubere und gut strukturierte Commit-Historie, das Codesystem eines Projekts lesbarer und verständlicher zu machen. Dies ist ein zentrales Element für ein gesundes, langfristiges Projekt!

Was interaktiver Rebase für Sie tun kann

Interaktiver Rebase hilft Ihnen, Ihre Commit-Historie zu optimieren und aufzuräumen. Er deckt viele verschiedene Anwendungsfälle ab, einige davon ermöglichen Ihnen Folgendes:

  • ein altes Commit-Nachrichten bearbeiten
  • einen Commit löschen
  • mehrere Commits zusammenführen/kombinieren
  • Commits neu ordnen
  • Reparieren alter Commits
  • Teilen/Eröffnen alter Commits zur Bearbeitung

Wann sollte man einen interaktiven Rebase verwenden (und wann nicht!)

Wie einige andere Git-Tools schreibt der interaktive Rebase „Geschichte“ um. Das bedeutet, dass beim Bearbeiten einer Reihe von Commits mit interaktivem Rebase dieser Teil Ihrer Commit-Historie umgeschrieben wird: die SHA-1-Hashes der Commits werden sich geändert haben. Sie sind sozusagen komplett neue Commit-Objekte.

Dieser Umstand fordert eine einfache, aber wichtige Regel heraus: Verwenden Sie keinen interaktiven Rebase (oder andere Tools, die die Geschichte neu schreiben) für Commits, die Sie bereits mit Ihren Kollegen in einem Remote-Repository geteilt haben. Verwenden Sie ihn stattdessen, um Ihre eigenen, lokalen Commits zu bereinigen – wie in einer Ihrer eigenen Feature-Branches – bevor Sie sie in einen Team-Branch integrieren.

Der Grundmechanismus einer interaktiven Rebase-Operation

Obwohl interaktiver Rebase für viele verschiedene Dinge verwendet werden kann, ist der Grundablauf immer derselbe. Sobald Sie diesen Grundmechanismus verstanden haben, wird der interaktive Rebase seinen „mysteriösen“ Ruf verlieren und zu einem wertvollen, zugänglichen Element in Ihrer Werkzeugkiste werden.

Schritt 1: Wo soll die Sitzung beginnen?

Die erste Frage, die Sie beantworten müssen, ist: „Welchen Teil meiner Commit-Historie möchte ich bearbeiten?“ Dies gibt Ihnen Auskunft darüber, wo Sie Ihre interaktive Rebase-Sitzung beginnen sollten. Nehmen wir ein praktisches Beispiel und sagen wir, wir möchten eine alte Commit-Nachricht bearbeiten (was wir tatsächlich gleich tun werden).

Unsere Ausgangssituation ist unten dargestellt, wo wir eine alte Commit-Nachricht über einen interaktiven Rebase bearbeiten.

Um die Commit-Nachricht in C2 ändern zu können, müssen wir unsere interaktive Rebase-Sitzung bei ihrem Eltern-Commit (oder sogar davor, wenn du möchtest) starten. In diesem Beispiel würden wir C1 als Startpunkt für unsere interaktive Rebase-Sitzung verwenden.

Schritt 2: Starten der tatsächlichen Sitzung!

Der Start der tatsächlichen Sitzung ist ziemlich einfach:

$ git rebase -i HEAD~3

Wir verwenden den git rebase-Befehl mit dem -i-Flag (um anzugeben, dass wir tatsächlich eine „interaktive“ Sitzung wünschen) und geben den Basis-Commit an (den wir in unserem ersten Schritt oben ermittelt haben). In diesem Beispiel habe ich HEAD~3 verwendet, um den Commit anzugeben, der „3 hinter dem HEAD-Commit“ liegt. Alternativ hätte ich auch einen spezifischen SHA-1-Hash angeben können.

Schritt 3: Git sagen, was du tun möchtest

Nach dem Start der interaktiven Rebase-Sitzung wird ein Editor-Fenster angezeigt, in dem Git eine Reihe von Commits auflistet — von dem neuesten Commit bis hin zum (jedoch nicht einschließlich) dem von dir als Basis-Commit in Schritt 1 gewählten Commit.

In diesem Schritt sind zwei wichtige Dinge zu beachten:

  1. Commits sind in umgekehrter Reihenfolge aufgelistet! Der neueste Commit, den wir am oberen Ende erwarten würden, erscheint am unteren Ende der Liste. Keine Sorge: dein Git-Repository ist in Bestform! 🥳 Denke daran, dass wir im Prozess einer interaktiven Rebase-Operation stecken, und dies erfordert, dass Git die Commits am Ende der Operation von ältesten bis jüngsten neu anwendet.
  2. Machen Sie keine tatsächlichen Änderungen in diesem Bearbeitungsfenster! Obwohl Sie vielleicht daran interessiert sind, einfach loslegen und die Commit-Nachricht in diesem Bearbeitungsfenster zu ändern (schließlich wollen wir das ja tun…), müssen Sie ein wenig Geduld haben. Hier werden wir Git nur sagen, was wir tun möchten — aber die tatsächliche Änderung nicht vornehmen. Ich werde diesen Punkt gleich praktisch demonstrieren!

Nachdem wir diese theoretische Übersicht abgeschlossen haben, lassen Sie uns gemeinsam einige praktische Fälle betrachten!

Bearbeiten einer alten Commit-Nachricht

Eine der sehr beliebten Anwendungsfälle eines interaktiven Rebasings ist, dass Sie eine alte Commit-Nachricht nachträglich bearbeiten können. Sie könnten wissen, dass git commit --amend Ihnen auch ermöglicht, eine Commit-Nachricht zu ändern — aber nur, wenn es sich um den ganz letzten Commit handelt. Für jeden älteren Commit müssen wir interaktives Rebase verwenden!

Schauen wir uns ein konkretes Szenario an. Folgendes ist ein Bild einer schlechten Commit-Nachricht, die korrigiert werden muss.

Hinweis: Für eine bessere Übersicht und klarere Visualisierung verwende ich in einigen meiner Screenshots den Tower Git Desktop-Client. Sie benötigen Tower für dieses Tutorial nicht.

In unserem Beispiel möchten wir die Nachricht des Commits mit dem aktuellen Titel „Optimize markup structure in index…“ bearbeiten.

Unser erster Schritt ist die Bestimmung des Basis-Commits für den Start dieser interaktiven Rebase-Sitzung. Da wir zumindest zurück zum Elternteil unseres „schlechten Apfels“ Commits gehen müssen, beginnen wir unsere Sitzung bei HEAD~3 (drei Commits hinter dem HEAD-Commit, der mit „Headlines ändern …“ betitelt ist):

$ git rebase -i HEAD~3

Gleich nach Ausführung dieses Befehls öffnet sich dein bevorzugter Editor und zeigt dir die ausgewählte Liste von Commits (indem ein Basis-Commit bereitgestellt wird).

Zur Erinnerung: Auch wenn du dazu neigst, ändern wir nicht die Commit-Nachricht hier. Wir markieren lediglich die entsprechende Zeile mit einem „Aktion-Schlüsselwort“. In unserem Fall möchten wir das Commit reworden (was bedeutet, dass wir die Commit-Nachricht ändern möchten, aber den Rest des Commits unverändert lassen).

Sehr praktisch sind alle verfügbaren Aktion-Schlüsselwörter am unteren Rand dieses Fensters dokumentiert — also ist es nicht nötig, etwas auswendig zu lernen!

Nachdem du das Standard-pick-Schlüsselwort (das „nehme das Commit so wie es ist“ bedeutet) durch dein bevorzugtes Aktion-Schlüsselwort ersetzt hast, kannst du das Fenster einfach speichern und schließen.

Danach öffnet sich ein neues Editor-Fenster, das die aktuelle Commit-Nachricht enthält. Endlich dürfen wir tun, was wir ursprünglich vorhatten: diese alte Commit-Nachricht bearbeiten!

Nachdem wir unsere Änderung vorgenommen und das Editor-Fenster gespeichert und geschlossen haben, ist die interaktive Rebase-Sitzung abgeschlossen — und unsere Commit-Nachricht ist aktualisiert! 🎉

Löschen eines unerwünschten Commits

Der interaktive Rebase erlaubt es auch, einen alten Commit aus deiner Historie zu löschen, den du nicht mehr (oder nicht) benötigst. Stell dir vor, du hast versehentlich ein persönliches Passwort in einem kürzlichen Commit enthalten: sensible Informationen wie diese sollten in den meisten Fällen nicht in einem Codebase enthalten sein.

Denke auch daran, dass das bloße Löschen der Information und ein erneutes Commiten das Problem nicht wirklich löst: dies würde bedeuten, dass das Passwort immer noch im Repository gespeichert ist, in Form deines alten Commits. Was du wirklich willst, ist dieses Stück Daten sauber und vollständig aus dem Repository zu entfernen!

Beginnen wir mit der Bestimmung des Basis-Commits für unsere interaktive Rebase-Sitzung. Da wir mindestens beim Elternteil des schlechten Commits beginnen müssen, verwenden wir den „Optimize markup structure…“-Commit als Basis:

$ git rebase -i 6bcf266b

Beachte, dass ich dieses Mal einen konkreten SHA-1-Hash in der git rebase -i-Befehls verwendet habe. Anstelle des Commit-Hashes hätte ich natürlich auch HEAD~2 verwenden können, um auf diesen Commit zu verweisen.

Nach Ausführung dieses Befehls erhalten wir wieder eine Liste von Commits.

Dieses Mal verwenden wir das drop-Aktion-Schlüsselwort, um den unerwünschten Commit loszuwerden. Alternativ könnten wir in diesem speziellen Fall auch einfach die ganze Zeile aus dem Editor löschen. Wenn eine Zeile (die einen Commit darstellt) beim Speichern und Schließen des Fensters nicht mehr vorhanden ist, wird Git den entsprechenden Commit löschen.

Wie auch immer du es anstellst, nachdem du den Editor-Fenster gespeichert und geschlossen hast, wird der Commit aus der Historie deines Repositories gelöscht!

Zusammenführen mehrerer Commits in Einen

Ein weiterer Anwendungsfall für einen interaktiven Rebase ist, wenn Sie mehrere separate Commits zu einem einzigen kombinieren möchten. Bevor wir uns darauf einlassen, wie dies funktioniert, lassen Sie uns einige Momente lang darüber sprechen, wann oder warum dies von Wert sein könnte.

Im Allgemeinen ist es nicht eine gute Strategie, Commits „größer“ zu machen (indem man mehrere zu einem kombiniert). Die Faustregel lautet, Commits so klein wie möglich zu halten, denn „klein“ bedeutet „einfacher zu lesen und zu verstehen“. Es gibt jedoch Situationen, in denen dies trotzdem Sinn machen kann. Hier sind zwei Beispiele:

  • Stellen Sie sich vor, Sie hätten ein Problem mit einem älteren Commit festgestellt. Sie könnten dann einen neuen Commit erstellen, der das Problem behebt. In einer solchen Situation macht es viel Sinn, diese Commits zu einem einzigen zu kombinieren: Der neue Commit war ja letztendlich nur ein „Pflaster“, um ein Problem zu beheben, das eigentlich gar nicht da sein sollte. Durch die Kombination dieser Commits sieht es so aus, als hätte es das Problem nie gegeben!
  • Ein weiteres Beispiel ist, wenn Sie feststellen, dass Sie Dinge ein wenig zu granular gemacht haben. Kleine Commits sind zwar gut und schön, aber wenn Sie Ihre Commit-Historie mit vielen unnötig kleinen Commits überschütten, übertreiben Sie es.

Die Begründung ist in beiden Beispielen dieselbe: Durch die Kombination von zwei (oder mehreren) Commits, die eigentlich ein einziger sein sollten, erzeugen Sie eine sauberere und lesbarere Commit-Historie!

Lassen Sie uns gemeinsam ein praktisches Beispiel durchgehen und die unten dargestellte Situation als Ausgangssituation nehmen.

Angenommen, es macht semantisch mehr Sinn, diese beiden Commits als einen einzigen zu betrachten. Mit dem squash-Tool des interaktiven Rebase können wir sie tatsächlich kombinieren:

$ git rebase -i HEAD~3

Inzwischen bist du wahrscheinlich schon an das Folgende gewöhnt: Ein Editorfenster öffnet sich mit einer Liste von Commits.

I already mentioned that we’re going to use the squash action keyword in this case. There’s an important thing to know about how squash works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash keyword in our example.

Nach dem Speichern und Schließen dieses Fensters öffnet sich ein neues. Das liegt daran, dass wir durch das Kombinieren mehrerer Commits natürlich auch einen neuen erstellen. Und dieser benötigt wie jeder andere Commit auch eine Commit-Nachricht!

Was du im obigen Screenshot siehst, ist, was Git für uns vorbereitet hat: Es hat die Commit-Nachrichten der ursprünglichen Commits zusammen mit einigen Kommentaren kombiniert. Du kannst die alten Nachrichten löschen und ganz neu beginnen – oder sie behalten und weitere Informationen hinzufügen.

Nach dem Speichern und Schließen dieses Editorfensters können wir stolz feststellen: Was einst zwei separate Commits waren, ist jetzt ein einziger!

Die Macht des interaktiven Rebase nutzen

I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).

Wenn du mehr erfahren möchtest, empfehle ich sehr die “First Aid Kit for Git”. Es ist eine (kostenlose) Sammlung von kurzen Videos, die dir zeigen, wie man in Git aufräumt und Fehler rückgängig macht.

Viel Spaß!

Häufig gestellte Fragen (FAQs) zum Git Interactive Rebase

Was ist der Unterschied zwischen Git Rebase und Git Merge?

Git Rebase und Git Merge sind zwei verschiedene Methoden, um Änderungen aus einer Zweig in einen anderen zu integrieren. Git Merge ist ein einfacher Weg, um Code aus zwei verschiedenen Zweigen zu kombinieren. Es erstellt einen neuen Commit in der Historie, der die chronologische Reihenfolge der Commits beibehält. Andererseits ist Git Rebase eine Möglichkeit, eine Reihe von Commits auf einen neuen Basis-Commit zu verschieben oder zu kombinieren. Es ist, als ob man sagen würde: „Ich möchte meine Änderungen auf dem stehen, was alle anderen getan haben.“ Mit anderen Worten, erlaubt es Ihnen, die Änderungen aus dem aktuellen Zweig oben auf einen anderen Zweig zu legen.

Wie kann ich einen Git Rebase rückgängig machen?

Wenn Sie einen Git Rebase rückgängig machen möchten, können Sie den Befehl git reflog verwenden, um den Commit zu finden, zu dem Sie zurückkehren möchten, und dann den Befehl git reset --hard HEAD@{number} verwenden. Der Befehl git reflog zeigt eine Liste aller Änderungen, die am HEAD vorgenommen wurden, und der Befehl git reset ermöglicht es Ihnen, den aktuellen HEAD auf den angegebenen Zustand zu setzen.

Wozu dient Git Interactive Rebase?

Git Interactive Rebase ermöglicht es Ihnen, Commits auf vielfältige Weise zu ändern, wie z.B. Bearbeiten, Löschen und Zusammenführen. Sie können nicht nur die Commit-Nachricht ändern, sondern auch den tatsächlichen Code, falls Sie einen Fehler gemacht haben. Es ist ein leistungsfähiges Werkzeug, das Ihnen die volle Kontrolle über die Commit-Historie Ihres Projekts gibt.

Wie kann ich Commits mithilfe von Git Interactive Rebase zusammenführen?

Das Squashen ist das Zusammenführen mehrerer Commits zu einem. In Git kannst du Commits mit dem Befehl git rebase -i zusammenquetschen, gefolgt vom Commit-Hash, den du squash-en möchtest. Im daraufhin geöffneten Texteditor kannst du die Commits markieren, die du squash-en möchtest, indem du pick durch squash oder s neben jedem Commit ersetzt.

Welche Risiken gibt es beim Einsatz von Git Interactive Rebase?

Obwohl Git Interactive Rebase ein mächtiges Werkzeug ist, kann es gefährlich sein, wenn es nicht richtig eingesetzt wird. Es schreibt die Commit-Geschichte um, was problematisch sein kann, wenn du an einer öffentlichen Branch arbeitest, an der auch andere arbeiten. Es wird empfohlen, es nur auf lokalen Branches zu verwenden, die noch nicht gepusht wurden.

Wie kann ich Konflikte während eines Git Rebase lösen?

Während eines Rebase können Konflikte auftreten. Git wird anhalten und dir erlauben, diese Konflikte zu beheben, bevor es fortgesetzt wird. Du kannst Konflikte lösen, indem du die Dateien bearbeitest, um die konfliktbehafteten Änderungen zu beheben, und dann die gelösten Dateien mit git add hinzufügst. Nachdem alle Konflikte gelöst wurden, kannst du das Rebase mit git rebase --continue fortsetzen.

Kann ich Git Interactive Rebase verwenden, um einen Commit zu teilen?

Ja, du kannst Git Interactive Rebase verwenden, um einen Commit in kleinere aufzuteilen. Dies kann nützlich sein, wenn du in einem einzigen Commit mehrere Änderungen vorgenommen hast, aber später entscheidest, dass sie getrennte Commits hätten sein sollen.

Wie kann ich mit Git Interactive Rebase eine Commit-Nachricht bearbeiten?

Sie können eine Commit-Nachricht während eines interaktiven Rebases bearbeiten. In der Liste der Commits ersetzen Sie pick durch reword oder r neben dem Commit, den Sie bearbeiten möchten. Wenn Sie fortfahren, öffnet Git einen Texteditor für jeden mit reword markierten Commit, sodass Sie die Commit-Nachricht ändern können.

Was ist der Unterschied zwischen Git Rebase und Git Pull?

Git Pull ist ein Befehl, der Änderungen aus einem entfernten Repository abruft und in Ihrer aktuellen Branch-Integration. Auf der anderen Seite ist Git Rebase ein Befehl, der eine Reihe von Commits zu einem neuen Basiscommit bewegt oder kombiniert. Während beide Befehle dazu verwendet werden, Änderungen zu integrieren, tun sie dies auf unterschiedliche Weise.

Kann ich Git Interactive Rebase verwenden, um die Reihenfolge von Commits zu ändern?

Ja, Sie können die Reihenfolge von Commits mithilfe von Git Interactive Rebase ändern. In der Liste der Commits können Sie einfach die Reihenfolge der Zeilen ändern, um die Reihenfolge der Commits zu ändern. Dies kann nützlich sein, wenn Sie Ihre Commit-Historie logischer oder klarer gestalten möchten.

Source:
https://www.sitepoint.com/git-interactive-rebase-guide/