Verwenden Sie Git Rebase, um den Commit-Verlauf zu bereinigen.

  • Mit Git Rebase können Sie die Historie umschreiben und ordnen, um eine saubere und lineare Abfolge von Commits zu erstellen.
  • Interactive Rebase ermöglicht das einfache Löschen, Zusammenführen oder Neuanordnen von Commits und eliminiert so leere Tests und Commits.
  • Die Umschreibung der Geschichte erfordert eine Abstimmung mit dem Team und einen vorsichtigen Einsatz von erzwungenem Druck, um den Verlust der Arbeit anderer zu vermeiden.
  • Tools wie git reflog und git pull --rebase helfen Ihnen, sicher und reversibel mit Rebase zu arbeiten.

Git Rebase

Wer Git schon länger nutzt, kennt wahrscheinlich die Historie voller nutzloser Commits, „WIP“-Meldungen, Schnelltests oder sogar leerer Commits, die nur erstellt wurden, um einen Hook oder eine Pipeline auszulösen. In solchen Momenten schaut man sich das Log an und denkt: „Das kann niemand verstehen.“Die gute Nachricht ist: Sie sind nicht allein. Das passiert uns allen, und genau dafür ist Unterstützung da. Git Rebase.

Das Interessante daran ist, dass es bei richtiger Anwendung Mit git rebase können Sie die Commit-Historie „bereinigen“.Gestalten Sie Ihre Historie übersichtlich, störungsfrei und deutlich leichter nachvollziehbar. Sie können Test-Commits löschen, mehrere zusammenführen, sie neu anordnen, Commit-Nachrichten korrigieren und sogar Änderungen per Forced Push vom Remote-Repository entfernen. Sehen wir uns anhand konkreter Beispiele an, wie Sie mit Rebase Ihre Historie von völligem Chaos in etwas Organisiertes und Lesbares verwandeln.

Was genau ist Git Rebase und warum beeinflusst es die Historie?

Wenn wir von Überholmanövern sprechen, meinen wir wörtlich … den Startpunkt eines Zweigs ändernGit nimmt die Commits aus Ihrem Branch und "reproduziert" sie nacheinander auf einer anderen Basis (normalerweise dem Branch). Haupt- oder einem aktualisierten Remote-Branch). Es ist, als ob man in der Zeit zurückgereist wäre und die Arbeit von einem anderen Commit aus fortgesetzt, aber die Änderungen beibehalten hätte.

Stellen Sie sich vor, Ihr Projekt enthält diese Story im Hauptzweig: A – B – CSie erstellen einen Funktionszweig und führen dann zwei Commits durch: D - E.Währenddessen fügt jemand im Hauptprogramm einen neuen Commit hinzu. FOhne Rebase würden Ihre Branches etwa so aussehen:

A---B---C---F (main)
A---B---C---D---E (feature)

Wenn Sie einen klassischen Merge Ihres Feature-Branches in den Hauptzweig durchführen, erhalten Sie einen zusätzlichen Merge-Commit, der häufig Folgendes erzeugt: verwickelte Geschichte mit mehreren gekreuzten Linien. Bei einem Rebase hingegen nimmt Git Ihre Commits D und E und wendet sie erneut auf F an:

A---B---C---F---D'---E' (feature reescrita)

Diejenigen D' und E' Das sind nicht exakt dieselben Commits wie D und E: Es sind „Kopien“ mit neuen Kennungen (Hashes). Deshalb sagen wir Rebase. schreibt die Geschichte umDas Ergebnis ist ein lineareres Protokoll ohne zwischenzeitliche Merge-Commits, die nur zusätzliches Rauschen verursachen.

Git Rebase

Warum Sie eine saubere Commit-Historie haben sollten

Eine geordnete Aktenführung ist nicht nur eine Frage der Ästhetik. Ein sauberes Protokoll erleichtert die tägliche Arbeit ungemein.Sie können auf einen Blick erkennen, was wann und warum getan wurde, ohne sich durch leere Merge-Commits oder kontextlose „Quick-Fix“-Meldungen klicken zu müssen.

Wenn Branches durch ständiges Zusammenführen vom Hauptzweig zusammengeführt werden, erhält man am Ende eine Reihe von Commits wie „Merge branch 'main' into feature-x“, die Sie liefern keine konkreten Informationen über Codeänderungen.Dies erschwert Aufgaben wie:

  • Ermitteln Sie den Commit, in dem der Fehler eingeführt wurde, indem Sie Werkzeuge zum Vergleichen von Dateienweil die Historie voller irrelevanter Fusionen ist.
  • Pull-Anfragen prüfenweil man zwischen redundanten Commits hin- und herspringen muss, um zu sehen, was sich tatsächlich geändert hat.
  • Die Entwicklung eines Merkmals versteheninsbesondere wenn es über viele kleine Test-Commits hinweg entwickelt wurde.

Git Rebase ist das ideale Werkzeug, um all diesen „Kram“ zu entfernen, bevor der Branch mit dem Rest des Teams geteilt wird. Das ist, als würde man seine Geschichte in die Waschmaschine stecken.Sie behalten die wichtigen Änderungen übersichtlich zusammengefasst und mit klaren Botschaften bei.

Wesentliche Unterschiede zwischen git merge und git rebase

Um vollständig zu verstehen, was Sie beim Verwenden von Rebase tun, lohnt es sich, dessen Verhalten mit dem von … zu vergleichen. Git-ZusammenführungBeide dienen der Integration von Veränderungen, jedoch auf unterschiedliche Weise und mit wichtigen Auswirkungen auf die Aufzeichnungen.

Mit fusionierenGit erstellt einen neuen Merge-Commit mit zwei Eltern-Commits: dem aktuellen Stand Ihres Branches und dem aktuellen Stand des Branches, mit dem Sie mergen. Die resultierende Historie Behält exakt die ursprüngliche Abfolge der Commits beiAber es kann am Ende voller paralleler Verzweigungen und Zusammenführungen sein.

Mit zurückweisenAnstatt einen Merge-Commit zu erstellen, wendet Git Ihre Commits nacheinander auf die neue Datenbank an. Dadurch wird Folgendes generiert: neue Commits mit neuen Hashesselbst wenn die Codeänderungen identisch sind.

In der Praxis:

  • Merge Es bewahrt die Geschichte genau so, wie sie sich zugetragen hat, mit allen Querverweisen und Verschmelzungen.
  • rebasieren Es erzeugt eine lineare und saubere Geschichte, als ob alles geradlinig verlaufen wäre.

Die Wahl lautet nicht „das eine ist besser als das andere“, sondern Für welche Situation eignet sich die jeweilige Lösung besser?Um bereits geteilte und geschlossene Branches zusammenzuführen, ist Mergen in der Regel sicherer. Um lokale Arbeitsbranches übersichtlich zu halten oder vor dem Öffnen eines Pull Requests, ist Rebase die beste Wahl.

Zusammenführen vs. Rebase

Anwendungsfälle, in denen Rebase seine Stärken ausspielt: Aktualisieren und Optimieren von Branches

Es gibt zwei Szenarien, in denen die meisten Entwickler täglich Rebase verwenden: Halten Sie Ihren Arbeitszweig mit dem Hauptzweig auf dem neuesten Stand. y Bereinige die Commits, bevor du sie teilst.Schauen wir sie uns genauer an.

Aktualisieren Sie Ihren Feature-Branch mit den neuesten Änderungen aus dem Hauptzweig.

Du arbeitest an einer neuen Funktion in deinem Branch, aber deine Kollegen machen derweil noch Commits in Haupt-Wenn Sie Ihre Änderungen integrieren möchten, besteht eine Möglichkeit darin:

git checkout tu-rama-feature
git merge main

Das funktioniert zwar, erzeugt aber bei jeder Synchronisierung einen Merge-Commit, was letztendlich zu Problemen führt. eine Geschichte voller sich wiederholender FusionenSollten Sie dies jedoch tun:

git checkout tu-rama-feature
git rebase main

Git wird Ihre Commits auf den letzten Stand des Hauptzweigs übertragen, so als hätten Sie den Zweig nach diesen Änderungen erstellt. Sie erhalten eine lineare Historie ohne zwischenzeitliche Merge-Commitsund die Rezension wird klarer sein.

Bereinigen Sie Ihre Commits, bevor Sie einen Pull Request öffnen.

Es kommt sehr häufig vor, dass während der Entwicklung einer Funktion Commits wie „Tippfehlerkorrektur“, „Pipeline-Tests“, „Weitere Änderungen am Login“ usw. entstehen. Das ist während der Arbeit in Ordnung, aber Das ist nicht die Art von Geschichte, die man zeigen möchte. wenn Sie einen Pull Request öffnen.

Interaktives Rebase ermöglicht Ihnen Diese Commits neu organisieren und gruppieren in etwas Logischeres. Zum Beispiel statt diesem:

- WIP: añadir login
- Más cambios login
- Corregir tests login
- Arreglar typo variable

Am Ende erhält man einen einzigen, gut beschriebenen Commit:

- Añadir funcionalidad completa de login de usuario con tests

Durch diese „Aufbereitung“ der Geschichte wird das Verständnis für Rezensenten deutlich erleichtert. was jeder Commit beiträgt und vereinfacht die Fehlersuche in der Zukunft.

Interaktives Rebase zum Umschreiben der Historie

Die Basisversion von Rebase verschiebt Ihre Commits einfach in eine andere Basis. Das Kronjuwel ist jedoch die interaktiver Überbau, wodurch ein Editor mit der Liste der letzten Commits geöffnet wird, sodass Sie entscheiden können, was mit jedem einzelnen Commit geschehen soll.

Üblicherweise beginnt man damit, anzugeben, wie viele Commits man vom aktuellen HEAD aus zurückgehen möchte. Zum Beispiel:

git rebase -i HEAD~6

Dieser Befehl weist Git an: „Nimm die letzten 6 Commits dieses Branches und bereite ein interaktives Rebase vor.“ Git öffnet daraufhin Ihren Standardeditor (Vim, Nano, VS Code usw.) mit einer Ausgabe wie dieser:

pick 7ed9c6e update version
pick ecb7ef3 empty commit 1
pick a323615 empty commit 2
pick 2c3d41d empty commit 3
pick d53c00f empty commit 4
pick 22dcc79 empty commit 5

# Rebase 549dd76..22dcc79 auf 549dd76 (6 Befehle)
#
# Befehle:
# p, pick = use commit
# r, umschreiben = Verwende den Commit-Befehl, aber bearbeite die Nachricht.
# e, bearbeiten Verwenden Sie „commit“ und „stop“, um es zu ändern.
# s, Kürbis = Zusammenführung im vorherigen Commit
# f, Fixup = wie Squash, aber die Nachricht wird verworfen
# x, exec = Shell-Befehl ausführen
# b, break = Rebase hier stoppen
# d, fallen lassen = Löschen Commit
#…

Beachten Sie ein wichtiges Detail: Die Reihenfolge in dieser Datei ist umgekehrt zu der im Git-Log.In der Datei ist der erste aufgeführte Commit (7ed9c6e) der älteste der sechs, der letzte (22dcc79) der aktuellste. Dies ist wichtig, um Verwirrung beim Löschen oder Neuanordnen von Commits zu vermeiden.

Entferne Test- oder leere Commits aus dem lokalen Verlauf

Angenommen, Sie haben zum Testen eines Git-Hooks leere Commits mit der Option erstellt. –allow-empty. Zum Beispiel:

git commit -m "commit with no changes" --allow-empty

Diese Option ermöglicht es Ihnen, einen Commit zu erstellen, selbst wenn keine Änderungen an den Dateien vorgenommen wurden, was für Testzwecke nützlich ist, aber Es überfrachtet die Historie mit Commits, die keinen wirklichen Wert haben.Stellen Sie sich vor, Ihr Protokoll sieht folgendermaßen aus:

git log --pretty=oneline --abbrev-commit

Und Sie erhalten:

22dcc79 (HEAD -> main, origin/main, origin/HEAD) empty commit 5
d53c00f empty commit 4
2c3d41d empty commit 3
a323615 empty commit 2
ecb7ef3 empty commit 1
7ed9c6e update version

In diesem Szenario möchten Sie nur den nützlichen "Update-Versions"-Commit behalten und alle anderen entfernen. leerer Commit Das waren nur Tests. Dazu führt man einen interaktiven Rebase der letzten 6 Commits durch:

git rebase -i HEAD~6

Der Editor öffnet sich mit den 6 Commits. Ihre Aufgabe ist es, die Zeilen zu entfernen, die den leeren Commits entsprechen. Das heißt, Sie lassen nur noch Folgendes übrig:

pick 7ed9c6e update version

# Rebase 549dd76..22dcc79 auf 549dd76 (6 Befehle)
# … Rest der Kommentare …

Wie im Hilfeteil der Datei selbst angegeben, Wenn Sie eine Zeile löschen, verschwindet dieser Commit aus dem Verlauf. In der neuen, überarbeiteten Version wird Git beim Speichern und Schließen des Editors nur den Commit der "Update-Version" reproduzieren und die anderen verwerfen.

Hochladen der neuen Story auf Origin: Verwendung von erzwungenem Push

Bisher wurden alle Rebase-Änderungen an Ihrer lokalen Kopie des Repositorys vorgenommen. Wenn Sie möchten, dass diese Bereinigung auch im Remote-Repository übernommen wird (z. B. in der Datei `/etc/rebase`), ... Ursprung/HauptSie müssen den Remote-Verlauf mit dem neuen Verlauf überschreiben.

Dies geschieht mit einem erzwungener SchubEine gängige Methode, dies anzuzeigen, ist die Verwendung des "+"-Zeichens vor dem Branch-Namen beim Pushen:

git push origin +main

Das Pluszeichen signalisiert Git, dass Ignoriere die Abweichung im Verlauf und überschreibe den Remote-Branch. mit Ihrer überarbeiteten Version. Wenn Sie einfach Folgendes versucht haben:

git push origin main

Git würde Sie warnen, dass Ihre lokale Historie kein direkter Nachfolger der Remote-Historie ist (weil Sie Commits mit rebase überschrieben haben) und den Push ablehnen, um Datenverlust zu vermeiden.

Es ist wichtig zu verstehen, dass nach diesem erzwungenen Anstoß Gelöschte Commits sind nicht mehr über origin/main erreichbar.Möglicherweise befinden sie sich noch in Reflogs oder lokalen Kopien von anderen Kollegen, aber aus praktischen Gründen haben Sie den Remote-Verlauf gelöscht.

Ernsthafte Warnung: Das Überschreiben gemeinsam genutzter Branches ist kein Spiel.

Das Umschreiben der Historie klingt zwar gut, um alles zu organisieren, hat aber eine wichtige Konsequenz: Beim Erstellen neuer Commits mit neuen Hashes, Man vergrault damit alle, die ihre Arbeit bereits auf den alten Commits aufgebaut hatten.Deshalb gibt es die berühmte goldene Regel:

Branches, die bereits von anderen geteilt und aktiv genutzt werden, sollten nicht rebaset werden.

In der Praxis bedeutet dies, dass die Verwendung von Rebase auf folgenden Anwendungen sicher ist:

  • Lokale Feature-Branches die Sie noch nicht veröffentlicht haben oder die nur Sie verwenden.
  • Aktuelle Verpflichtungen solche, von denen du weißt, dass sonst niemand auf sie angewiesen ist.

Und es ist eine ziemlich schlechte Idee, darüber zu sprechen:

  • Haupt-, Entwicklungs- oder jeder „offizielle“ Zweig aus dem Repository, das mehreren Personen als Grundlage dient.
  • Gemeinschaftsbüros wenn mehr als ein Entwickler Commits durchführt.

Wenn Sie die Historie eines gemeinsam genutzten Branches überschreiben und anschließend einen erzwungenen Push durchführen, werden andere Teammitglieder feststellen, dass Seine Zweige verweisen auf Commits, die im Remote-Repository nicht mehr existieren.Sie werden komplexere Operationen durchführen müssen (wie z. B. eine Neuberechnung auf Basis der neuen Historie oder ein Zurücksetzen), um das Chaos zu beheben.

Krafteinwirkung: besser mit Sicherheitsgurt

In vielen Fällen muss nach einem Rebase ein Push erzwungen werden. Die klassische Vorgehensweise ist:

git push --force origin tu-rama

Diese Variante überschreibt jedoch ohne Rückfrage alle Änderungen auf dem Remote-Server. Um versehentliches Überschreiben der Arbeit anderer zu vermeiden, bietet Git eine deutlich bessere Option: –force-with-lease.

Wenn Sie Folgendes tun:

git push --force-with-lease origin tu-rama

Git prüft zuerst, ob Die Fernbedienung befindet sich noch in dem Zustand, in dem Sie sie vermutet haben. Beim letzten Pull oder Fetch wird, falls seitdem neue Commits in den entsprechenden Branch übertragen wurden, der Push abgelehnt und nicht erzwungen. Dadurch wird verhindert, dass Sie die Änderungen anderer überschreiben.

Die Idee ist, Rebase und Force Push zu kombinieren, immer mit kühlem Kopf: nur in Filialen, die Sie kontrollieren und wann immer möglich, die Option „–force-with-lease“ als zusätzliche Sicherheitsebene zu verwenden.

Was tun, wenn ein Rebase fehlschlägt? Reflog hilft.

Das ist uns allen schon passiert: Man startet einen interaktiven Rebase, löscht oder ändert versehentlich etwas, löst einen Konflikt falsch und plötzlich… Es scheint, als hätten Sie einen Teil Ihrer Arbeit verloren.Bevor Sie in Panik geraten, denken Sie daran, dass Git ein Ass im Ärmel hat: Git-Reflog.

Das Reflog ist ein lokales Protokoll aller HEAD-Bewegungen: neue Commits, Resets, Rebase-Vorgänge, Merges usw. Dank ihm können Sie feststellen, wo sich Ihr Branch befand, bevor Sie ihn beschädigt haben, und mit einem Hard Reset zu diesem Punkt zurückkehren.

Der typische Ablauf wäre:

git reflog

Dort sehen Sie eine Liste von Einträgen mit etwa folgendem Inhalt:

abc1234 HEAD@{0}: rebase terminado
def5678 HEAD@{1}: checkout: moving from main to main
...

Sie identifizieren den Commit, an dem Sie sich vor dem Start des Rebase befanden (zum Beispiel, def5678) und du kehrst zu ihm zurück mit:

git reset --hard def5678

Somit Sie machen die Überlagerung vollständig rückgängig. und Sie kehren zum vorherigen Zustand zurück. Sie können einen laufenden Rebase auch abbrechen (wenn Sie sich mitten im Prozess befinden und ihn noch nicht abgeschlossen haben), indem Sie einfach Folgendes verwenden:

git rebase --abort

Dieser Befehl belässt Ihren Branch in dem Zustand, in dem er sich unmittelbar vor dem Start des aktuellen Rebase befand. Er eignet sich perfekt, wenn Konflikte auftreten, die Sie nicht wünschen, oder wenn Sie feststellen, dass es kein guter Zeitpunkt ist, fortzufahren.

Git pull vs. Git pull --rebase: Kleine Unterschiede, große Auswirkungen

Ein weiterer Punkt, der oft Zweifel aufwirft, ist der Unterschied zwischen git ziehen normal u git pull --rebaseBeide aktualisieren Ihren lokalen Branch vom Remote-Branch, jedoch auf unterschiedliche Weise.

Wenn du läufst:

git pull

Git benötigt zwei Schritte: Git holen um die Änderungen von der Fernbedienung zu übernehmen und dann ein Git-Zusammenführung um sie mit Ihrem aktuellen Branch zu kombinieren. Dies kann einen zusätzlichen Merge-Commit erzeugen, wenn Sie lokale Commits oberhalb des Remote-Branches haben, was wiederum Historie mit unnötigen Zusammenführungen.

Wenn Sie jedoch Folgendes ausführen:

git pull --rebase

Git führt das Abrufen durch und dann Übertragen Sie Ihre lokalen Commits in die aktualisierte Version auf dem Remote-Server.Das Ergebnis ist ähnlich dem, als ob Sie Folgendes getan hätten git fetch gefolgt von git rebase origin/mainund sorgt für eine sauberere, linearere Historie.

Deshalb konfigurieren viele Teams Git so, dass beim Pull-Vorgang standardmäßig ein Rebase durchgeführt wird. Es ist eine einfache Methode, um Automatische Merge-Commits vermeiden die nicht viel beitragen.

Dateien oder Bilder aus dem Verlauf löschen: allgemeine Idee

Manchmal liegt das Problem nicht in einem unschönen Commit, sondern Eine Datei, die niemals ins Repository hätte gelangen dürfen.Falsches Bild, falsche Zugangsdaten, riesige Dateien usw. Man ist versucht, auf GitHub nach dem Papierkorbsymbol zu suchen, aber wenn dieses deaktiviert ist und Meldungen wie „Du befindest dich in einem Branch“ angezeigt werden, liegt das daran, dass… GitHub erlaubt es nicht, den Verlauf auf diese Weise zu löschen..

Die korrekte Methode beinhaltet üblicherweise das Umschreiben der Browserhistorie von Ihrem lokalen Rechner aus (mit interaktivem Rebase oder Tools wie …). Git Filter-Repo) und führen Sie dann einen erzwungenen Push durch. In GitHub Desktop können Sie auch Branches und Commits verwalten, aber die Operation von Eine Datei vollständig aus allen Commits entfernen Dies beinhaltet das Umschreiben der Geschichte in ähnlicher Weise, wie wir es hier beobachten.

Kurz gesagt: Wenn Sie das falsche Bild oder eine sensible Datei hochgeladen haben und diese aus dem Verlauf "verschwinden" lassen möchten, reicht es nicht aus, sie einfach im letzten Commit zu löschen: Die Commits, in denen es eingeführt wurde, müssen neu geschrieben werden. Und dann den Stoß ausführen. Es ist ein heikler Vorgang und sollte ruhig und in Abstimmung mit Ihrem Team durchgeführt werden.

Praktischer Ablauf zum Üben von Überholmanövern, ohne etwas kaputt zu machen

Am besten übt man Überholmanöver in einer kontrollierten Umgebung, ohne andere bei der Arbeit zu stören. Ein einfacher Ablauf wäre:

  1. Erstelle einen neuen Branch von main mit git checkout -b my-tests-branch.
  2. Führe mehrere kleine Commits durch (dabei kann es sich um triviale Änderungen oder Testdateien handeln).
  3. Simulieren Sie den Fortschritt im Hauptprojekt, indem Sie dort neue Commits erstellen (oder jemanden anderen damit beauftragen).
  4. Wechseln Sie zurück zu Ihrem Testzweig und führen Sie Folgendes aus: git rebase main um zu sehen, wie Ihre Commits neu positioniert werden.
  5. versuche a git rebase -i HEAD~3 Die Möglichkeit, einen der letzten Commits zu kombinieren, umzubenennen oder zu löschen.

Mit dieser Übung werden Sie sehen, wie Verändere den Verlauf vorher und nachherWie Git auf Konflikte reagiert und wie Sie bei Bedarf mithilfe von `reflog` zu vorherigen Zuständen zurückkehren können. Je mehr Übung Sie lokal haben, desto sicherer werden Sie bei der Anwendung dieser Techniken auf echte Projektzweige sein.

Die Beherrschung von Git Rebase ermöglicht es Ihnen, eine unübersichtliche Historie voller leerer Commits, unnötiger Merges und bedeutungsloser Meldungen in eine klare und lesbare Abfolge wichtiger Änderungen zu verwandeln. Durch interaktives Rebase, das Löschen von Test-Commits, das Gruppieren verstreuter Arbeiten, das lineare Aktualisieren von Branches und den Einsatz von Tools wie Reflog und erzwungenen Pushes mit `--force-with-lease` können Sie Ihr Repository in einem deutlich besseren und professionelleren Zustand halten. Wichtig ist dabei, diese Techniken nur auf Branches anzuwenden, die Sie kontrollieren, und das Team vor dem Überschreiben der gemeinsamen Historie zu informieren.

Versionsverlauf in Drive: So nutzen Sie ihn und bewährte Vorgehensweisen
Verwandte Artikel:
Versionsverlauf in Drive: Erweiterte Nutzung und bewährte Vorgehensweisen

Als bevorzugte Quelle hinzufügen