Verlorene Commits mit Git Reflog wiederherstellen
Stellen Sie verlorene Git-Commits mit dem reflog wieder her: git reflog findet verwaiste Commits, macht Hard Resets und Rebases rückgängig und stellt Branches wieder her.
Um einen verlorenen Commit wiederherzustellen, führen Sie git reflog aus, kopieren den Hash des gewünschten Commits und stellen ihn mit git checkout -b recovered <hash> wieder her.
Sie meinten HEAD~1, tippten HEAD~2 – und sahen zu, wie drei Stunden Arbeit aus git log verschwanden. Die wenigen Sekunden zwischen dem Drücken der Enter-Taste und der Erinnerung daran, dass es das Reflog gibt, sind die schlimmsten in Git. Wenn Sie git reset --hard ausführen, einen Rebase vermasseln oder einen Branch löschen, werden Ihre Commits so gut wie nie zerstört: Sie sind lediglich verwaist, und ihre Hashes stehen weiterhin in Ihrem Reflog. Dieser Leitfaden liefert Ihnen das schnelle Wiederherstellungsrezept für die drei Szenarien, die Panik auslösen, und danach die harten Grenzen, die Sie kennen sollten, damit Sie die Arbeit nicht ein zweites Mal verlieren. Jeder Befehl unten ist zum Kopieren und Einfügen bereit.
Die wichtigsten Erkenntnisse
git reflogprotokolliert jede Bewegung vonHEADin Ihrem lokalen Repository (Commit, Checkout, Reset, Rebase, Merge) – ein „verlorener” Commit ist also meist nur eingit reset --hard <hash>davon entfernt, wieder da zu sein.- Die sicherste Wiederherstellung ist
git checkout -b recovered <hash>: Bauen Sie den Commit auf einem neuen Branch wieder auf und prüfen Sie ihn, bevor Sie Ihren eigentlichen Branch anfassen. - Das Reflog kann keine nicht committeten Änderungen im Arbeitsverzeichnis wiederherstellen, weil Git sie nie in einer Ref festgehalten hat.
- Standardmäßig behält Git erreichbare Reflog-Einträge 90 Tage und nicht erreichbare 30 Tage. Stellen Sie also zügig wieder her und führen Sie
git gcnicht aus, bevor Sie Ihre Commits zurückhaben. - Das Reflog ist strikt lokal und wird nie gepusht. Es kann daher Ihre eigene verlorene Arbeit retten, aber nicht die nicht gepushten Commits eines Teammitglieds.
Wie funktioniert Git Reflog?
Das Reflog von Git ist ein lokales Protokoll jeder Position, die Ihre Branch-Spitzen und andere Refs eingenommen haben. Jeder Commit, Checkout, Reset, Rebase und Merge bewegt HEAD und wird protokolliert. Wenn ein Commit also „verloren” geht (das heißt: kein Branch und kein Tag zeigt mehr auf ihn), ist er lediglich verwaist, nicht gelöscht – und sein Hash steht weiterhin im Reflog und wartet darauf, wieder angebunden zu werden.
Führen Sie den Befehl ohne Argumente aus, um die Historie von HEAD zu sehen:
git reflog
b58145c HEAD@{0}: reset: moving to HEAD~2
dd7c37e HEAD@{1}: commit: one more commit
b5b3286 HEAD@{2}: checkout: moving from main to feature
b58145c HEAD@{3}: commit: very important commit
Lesen Sie jede Zeile so: Kurz-Hash, der HEAD@{n}-Index (wie viele Bewegungen zurück dieser Eintrag liegt) und eine Beschreibung der Operation. In der Ausgabe oben ist HEAD@{0} das destruktive reset, das gerade passiert ist, und HEAD@{1} (dd7c37e) ist der Commit, von dem es weggesprungen ist – genau der, den Sie zurückhaben wollen. Unter der Haube führt git reflog show dasselbe aus wie git log -g --abbrev-commit --pretty=oneline, und es akzeptiert jede Ref: git reflog show main liefert Ihnen also die Historie eines einzelnen Branches.
Discover how at OpenReplay.com.
Wiederherstellung nach einem versehentlichen Hard Reset
Ein git reset --hard verschiebt Ihren Branch-Pointer, lässt den alten Commit im Object Store aber intakt. Finden Sie ihn im Reflog und setzen Sie den Pointer erneut darauf. Der Commit direkt vor dem Reset ist der verlorene – üblicherweise HEAD@{1}.
git reflog
# HEAD@{0}: reset: moving to HEAD~2
# HEAD@{1}: commit: one more commit <-- this hash
git checkout -b recovered dd7c37e
Die sicherste Wiederherstellung besteht darin, zu prüfen, bevor Sie überschreiben: Führen Sie git checkout -b recovered <hash> aus, um den Commit auf einem neuen Branch wieder aufzubauen, verifizieren Sie ihn mit git log und entscheiden Sie erst dann, ob Sie Ihren eigentlichen Branch verschieben. Sobald Sie sicher sind, können Sie den Branch direkt umsetzen:
git reset --hard dd7c37e # or: git reset --hard HEAD@{1}
Warnung vor doppeltem Verlust: git reset --hard verwirft alle aktuellen nicht committeten Änderungen in Ihrem Arbeitsverzeichnis. Wenn Ihr Arbeitsbaum nicht clean ist, nutzen Sie zuerst git stash oder den Weg über einen neuen Branch. Andernfalls verursacht der Wiederherstellungsbefehl einen zweiten Verlust. Direkt nach einem Reset können Sie außerdem git reset --hard ORIG_HEAD verwenden, denn git reset speichert die vorherige Spitze des Branches in ORIG_HEAD, bevor es sie verschiebt.
Einen fehlgeschlagenen Rebase zurücknehmen
Ein Rebase schreibt Historie um, und ein falsch aufgelöster Konflikt kann stillschweigend Commits verschlucken. Das Reflog hält die Spitze von vor dem Rebase fest. Nach einem fehlgeschlagenen Rebase bringt git reset --hard ORIG_HEAD Ihren Branch zurück an den Ausgangspunkt. Allerdings wird ORIG_HEAD vom nächsten Reset, Rebase oder Merge überschrieben – wenn Sie seither einen solchen Befehl ausgeführt haben, suchen Sie die Pre-Rebase-Spitze stattdessen in git reflog.
git reflog
# HEAD@{0}: rebase (finish): returning to refs/heads/feature
# HEAD@{1}: rebase (pick): one more commit
# HEAD@{2}: rebase (start): checkout main
# HEAD@{3}: checkout: moving from main to feature <-- pre-rebase tip
git reset --hard HEAD@{3}
Achten Sie auf den Eintrag rebase (start); die Zeile unmittelbar davor zeigt Ihren Branch, wie er vor dem Rebase aussah. Wenn Sie nur bestimmte Commits zurückhaben wollen, die der Rebase verworfen hat, anstatt das Ganze rückgängig zu machen, holen Sie sich deren Hashes aus dem Reflog und spielen Sie sie erneut ein:
git cherry-pick <hash>
Einen gelöschten Branch wiederherstellen
Das Löschen eines Branches entfernt die Ref, nicht die Commits. Sein letzter Commit erscheint weiterhin im Reflog von HEAD (aus der Zeit, als Sie ihn zuletzt ausgecheckt haben). Suchen Sie also diesen Hash und erstellen Sie den Branch an dieser Stelle neu.
git reflog
# HEAD@{0}: checkout: moving from example-branch to main
# HEAD@{1}: commit: very important commit <-- last commit on deleted branch
git checkout -b example-branch b5b3286 # or HEAD@{1}
git checkout -b <branch> <hash> erstellt den Branch neu und lässt ihn auf den wiederhergestellten Commit zeigen – mit intakter Historie. Wenn Sie sich an einen Teil einer Commit-Message erinnern, aber nicht an den Hash, durchsucht git log --oneline -g --grep='<fragment>' das Reflog danach. (git switch -c ist das moderne Äquivalent zu checkout -b; beide funktionieren, und checkout ist nicht deprecated.)
Was kann Git Reflog nicht wiederherstellen?
Das Reflog kann alles wiederherstellen, was HEAD oder eine Branch-Spitze bewegt hat (Commits, Resets, Rebases, gelöschte Branches), aber es kann keine nicht committeten Änderungen im Arbeitsverzeichnis wiederherstellen, weil Git sie nie in einer Ref festgehalten hat. Wenn eine Änderung nie committet wurde, gibt es kein Ref-Update, auf das das Reflog zurückverweisen könnte – eine Suche im Reflog wird also nichts zutage bringen.
| Reflog KANN wiederherstellen | Reflog KANN NICHT wiederherstellen |
|---|---|
Commits, die durch reset --hard verwaist sind | Nicht committete Änderungen im Arbeitsbaum |
| Commits, die ein fehlgeschlagener Rebase verworfen hat | Gestagte, aber nicht committete Änderungen |
| Gelöschte lokale Branches (aus der jüngeren Vergangenheit) | Nicht gepushte Commits eines Teammitglieds |
| Ihre lokale Sicht auf ein force-gepushtes Remote | Einträge, die bereits abgelaufen und per gc entfernt sind |
Drei weitere Einschränkungen bestimmen die Wiederherstellung:
- Es ist lokal und temporär. Das Reflog existiert nur in Ihrem
.git-Verzeichnis und wird nie gepusht. Es rettet daher Ihre eigene Arbeit, aber nicht die nicht gepushten Commits eines Teammitglieds. - Einträge laufen ab. Standardmäßig behält Git erreichbare Reflog-Einträge 90 Tage und nicht erreichbare 30 Tage – gesteuert über
gc.reflogExpireundgc.reflogExpireUnreachable. Verwaiste Commits überleben bis zum Ablauf plus einem Garbage-Collection-Durchlauf. Stellen Sie also zügig wieder her und führen Siegit gcnicht aus, bevor Sie fertig sind. - Stellen Sie zuerst auf einem neuen Branch wieder her. Machen Sie
git checkout -b recovered <hash>zu Ihrem Standardvorgehen, damit Sie prüfen können, bevor Sie einen gemeinsam genutzten Branch verändern. Und schreiben Sie aussagekräftige Commit-Messages: Das Reflog zeigt sie an, und „Fix login bug” ist deutlich leichter zu finden als eine nichtssagende Beschreibung.
Bonus (nach einem Force-Push): Der Remote-Server hat kein Reflog, das Sie lesen könnten – Ihre lokale Tracking-Ref aber schon. Um Commits wiederherzustellen, die ein Force-Push auf einem Remote gelöscht hat, prüfen Sie Ihren lokalen Verlauf mit git reflog show origin/<branch>. Der Eintrag unmittelbar vor dem Force-Push enthält die alte Spitze.
Fazit
Das Reflog ist Gits lokales Sicherheitsnetz, und es verwandelt fast jeden „Ich habe meine Arbeit verloren”-Moment in eine Zwei-Befehl-Lösung: Log lesen, Pointer auf den Hash setzen. Das Einzige, was es nicht retten kann, ist Arbeit, die Sie nie committet haben – die nachhaltige Lehre lautet also: früh und häufig committen. So ist garantiert immer ein Reflog-Eintrag zu finden. Wenn das Terminal Ihnen das nächste Mal einen Schrecken einjagt, führen Sie vor allem anderen git reflog aus.
FAQs
Was ist der Unterschied zwischen git reflog und git log?
git log zeigt die Commit-Historie, die von einer Branch-Spitze aus erreichbar ist, und folgt dabei den Parent-Pointern – verwaiste Commits erscheinen darin also nie. git reflog zeigt jede Position, die HEAD oder eine Ref in Ihrem lokalen Repository eingenommen hat: Commits, Checkouts, Resets, Rebases und Merges, einschließlich Commits, auf die kein Branch mehr zeigt. Deshalb kann das Reflog einen Commit nach einem Hard Reset finden, während git log das nicht kann: Der Commit ist verwaist, aber sein Ref-Update ist weiterhin protokolliert.
Funktioniert git reflog nach dem Klonen eines Repositories?
Nein. Das Reflog wird ausschließlich in Ihrem lokalen .git-Verzeichnis gespeichert und nie gepusht oder gefetcht. Ein frischer Clone startet daher mit einem leeren Reflog, das nur Aktionen seit dem Klonen abdeckt. Es kann keine HEAD-Bewegungen von vor dem Clone anzeigen und auch nicht die lokale Historie eines Teammitglieds offenlegen. Das Reflog rettet Ihre eigene verlorene Arbeit in Ihrem eigenen Repository; es ist kein geteiltes oder remote-gestütztes Wiederherstellungswerkzeug.
Kann ich einen Commit wiederherstellen, nachdem die git-reflog-Einträge abgelaufen sind?
Nicht über das Reflog selbst. Standardmäßig laufen erreichbare Einträge nach 90 Tagen und nicht erreichbare nach 30 Tagen ab, und sobald ein Garbage-Collection-Durchlauf die verwaisten Objekte entfernt hat, sind sie wirklich weg. Davor können Sie den Hash manchmal noch mit git fsck --lost-found finden, das dangling Commits im Object Store auflistet. Der verlässliche Weg ist, zügig wiederherzustellen und git gc nicht auszuführen, bevor Ihre Commits zurück sind.
Wie finde ich einen verlorenen Commit, wenn ich seinen Hash nicht kenne?
Durchsuchen Sie direkt das Reflog. Führen Sie git log --oneline -g --grep='fragment' aus, um Reflog-Einträge nach einem Teil einer Commit-Message zu filtern, oder git reflog --date=relative, um Einträge zeitlich zu überblicken und die Operation zu identifizieren, die Sie zurücknehmen wollen. Für verwaiste Commits ohne Reflog-Eintrag listet git fsck --lost-found dangling Commits auf, die Sie mit git show inspizieren können, bevor Sie sie mit git checkout -b recovered <hash> auf einem neuen Branch wiederherstellen.