Einführung
Lerne, wie Git die History umschreibt: git commit --amend, git reflog und git rebase — was sie tun, wann sie einzusetzen sind und wie man sicher vorgeht.
In Git ist die History die Folge von Commits, die aufzeichnet, wie sich dein Projekt im Laufe der Zeit verändert hat. Jeder Commit wird durch einen eindeutigen Hash identifiziert und zeigt auf den Commit (oder die Commits), der davor stand. Meistens fügst du dieser Kette nur etwas hinzu. Manchmal musst du jedoch ändern, was bereits vorhanden ist — einen Tippfehler in einer Commit-Nachricht beheben, mehrere unordentliche Commits zu einem sauberen zusammenfassen oder Arbeit wiederherstellen, die du für verloren gehalten hast.
Dafür sind Gits Werkzeuge zum Umschreiben der History gedacht. Die drei, die du am häufigsten verwenden wirst, sind:
git commit --amend— ersetzt den letzten Commit.git reflog— zeigt jede Position, auf dieHEADgezeigt hat, damit du „verlorene" Commits wiederherstellen kannst.git rebase— spielt eine Reihe von Commits auf einer neuen Basis ab und ermöglicht dabei optional deren Bearbeitung.
Diese Seite gibt dir einen funktionierenden Überblick über jeden Befehl. Die oben verlinkten tiefergehenden Kapitel erläutern den vollständigen Satz an Optionen.
Die goldene Regel beim Umschreiben der History: Schreibe niemals Commits um, die du bereits in einen gemeinsam genutzten Branch gepusht hast. Das Umschreiben ändert Commit-Hashes, sodass jeder, der die alten Commits gezogen hat, Konflikte bekommt. Schreibe frei auf deinen eigenen lokalen Branches um; lass die gemeinsame History in Ruhe.
Den letzten Commit mit git commit --amend ändern
Es ist leicht, eine Datei zu vergessen, einen Tippfehler in einer Commit-Nachricht zu hinterlassen oder zu früh zu committen. Anstatt einen separaten „Fix"-Commit hinzuzufügen, ermöglicht git commit --amend, den letzten Commit durch einen korrigierten zu ersetzen.
Um nur die Nachricht des letzten Commits zu korrigieren:
git commit --amend -m "Add login validation"Um eine vergessene Datei zum letzten Commit hinzuzufügen, stage sie zuerst und amende dann ohne Änderung der Nachricht:
git add forgotten-file.js
git commit --amend --no-editDas Flag --no-edit behält die bestehende Nachricht und verwendet sie erneut. Im Hintergrund bearbeitet amend den alten Commit nicht direkt — es erstellt einen brandneuen Commit (mit einem neuen Hash) und verschiebt den Branch, um darauf zu zeigen. Der ursprüngliche Commit bleibt zurück, ohne Referenz.
Da durch das Amenden ein neuer Hash erzeugt wird, gilt dieselbe goldene Regel: Amende nur einen Commit, den du nicht in einen Branch gepusht hast, den andere Personen nutzen.
Eine vollständige Anleitung findest du unter git commit --amend.
Verlorene Commits mit git reflog wiederherstellen
Das Reflog (Referenz-Log) zeichnet jede Änderung an der Spitze deiner Branches und an HEAD auf — jeden Commit, Checkout, Reset, Merge und Rebase. Dies ist dein Sicherheitsnetz: Selbst nach einem Umschreiben oder einem Hard-Reset sind die alten Commits noch im Repository vorhanden, und das Reflog erinnert sich, wo sie waren.
Zeige das Log an mit:
git reflogEine typische Ausgabe sieht so aus:
a1b2c3d HEAD@{0}: commit: Add login validation
9f8e7d6 HEAD@{1}: reset: moving to HEAD~1
4c3b2a1 HEAD@{2}: commit: Work in progressJeder Eintrag zeigt einen Commit-Hash, eine HEAD@{n}-Referenz (wie viele Schritte zurück) und was passiert ist. Wenn du versehentlich einen Commit wegresettet hast, findest du ihn im Reflog und holst ihn zurück:
git reset --hard HEAD@{2}Der Befehl git reflog hat auch Unterbefehle wie git reflog show, git reflog expire und git reflog delete. Beachte, dass Reflog-Einträge lokal in deinem Repository sind und nach einer gewissen Zeit ablaufen (standardmäßig 90 Tage für erreichbare Einträge), sodass sie ein Wiederherstellungswerkzeug sind, keine dauerhafte Sicherung. Siehe git reflog und das verwandte Kapitel git reset für Details.
Auf eine neue Basis mit git rebase wechseln
git rebase nimmt eine Reihe von Commits und spielt sie auf einem anderen Basis-Commit ab. Sein Hauptvorteil ist eine lineare, lesbare History: Anstatt eines Merge-Commits, der zwei Branches verbindet, erscheint deine Arbeit als saubere Linie von Commits.
Es gibt zwei Modi:
- Standardmodus wendet die Commits deines aktuellen Branches auf die Spitze eines anderen Branches an. Dies ist die Alternative zum Mergen, wenn Updates von
mainintegriert werden sollen:
git rebase main- Interaktiver Modus ermöglicht das Neuanordnen, Bearbeiten, Kombinieren oder Verwerfen von Commits während der Wiedergabe. Füge die Option
-ihinzu und gib den Commit an, auf den du rebasen möchtest:
git rebase -i <base-branch>Ein häufiges interaktives Ziel sind „die letzten N Commits", zum Beispiel die letzten drei:
git rebase -i HEAD~3Eine ausführlichere Behandlung findest du unter git rebase und git rebase interactive.
Commits während eines interaktiven Rebase bearbeiten
Wenn du einen interaktiven Rebase startest, öffnet Git einen Editor, der die ausgewählten Commits auflistet, wobei jeder mit einer Aktion versehen ist. Du änderst das Aktions-Schlüsselwort, um zu steuern, was passiert:
pick— den Commit unverändert behalten (Standard).reword(r) — pausieren, um die Commit-Nachricht neu zu schreiben.squash(s) — diesen Commit in den vorherigen zusammenführen und deren Nachrichten in einem Editor kombinieren.fixup(f) — wiesquash, aber die Nachricht dieses Commits verwerfen und nur die des vorherigen behalten (keine Editor-Aufforderung).edit(e) — pausieren, damit du den Inhalt des Commits amenden kannst.drop(d) — den Commit vollständig entfernen.
Eine typische Rebase-To-Do-Liste sieht so aus:
pick a1b2c3d Add login form
squash 9f8e7d6 Fix typo in label
fixup 4c3b2a1 Adjust spacingHier werden der zweite und dritte Commit in den ersten gefaltet, sodass ein einziger übersichtlicher Commit übrig bleibt.
Warum umgeschriebene Commits neue IDs bekommen
Rebasen verschiebt die ursprünglichen Commits nicht — es erstellt neue Commits mit denselben Änderungen, aber anderen Eltern-Commits und daher anderen Hashes. Die alten Commits werden unreferenziert (sind noch eine Weile über das Reflog wiederherstellbar). Selbst Commits, die du mit pick markiert hast, erhalten neue IDs, wenn ein Commit vor ihnen in der Sequenz geändert wurde, weil sich ihr übergeordneter Commit geändert hat.

Genau deshalb ist die goldene Regel wichtig: Neue Hashes bedeuten eine abweichende History für alle, die die alten hatten.