Commits nach git reset --hard verschwunden – Reflog rettet sie
Nach git reset --hard oder einem verkorksten Rebase sind Commits scheinbar weg. Das Reflog kennt den alten Stand – so holst du ihn zurück.
Aufwand:
ca. 10 Min.
Voraussetzung:
Git, Terminal
Gilt für:
Git (alle aktuellen Versionen)
Das Symptom
Ein git reset --hard, ein Rebase, der anders lief als gedacht, oder ein
beherztes --amend – und danach fehlen die letzten Commits. git log zeigt
einen Stand von gestern, das Arbeitsverzeichnis sieht aufgeräumt aus, und die
Arbeit von drei Stunden ist nirgends mehr zu sehen. Der übliche nächste Schritt
ist, hektisch weitere Befehle auszuprobieren. Der schlechteste auch.
Die „Layer 8“-Wahrheit
Git löscht Commits nicht, wenn man ihm sagt, er solle woandershin zeigen. Ein
Branch ist ein Zeiger, ein Reset verschiebt diesen Zeiger, und die Commits, auf
die vorher gezeigt wurde, liegen danach weiterhin in der Objektdatenbank – nur
eben unerreichbar und damit unsichtbar. Für genau diesen Fall führt Git ein
zweites Protokoll: die Reference Logs. Sie halten fest, wann die Spitzen von
Branches und anderen Referenzen im lokalen Repository aktualisiert wurden, und
sie behalten das eine Weile – laut Dokumentation standardmäßig 90 Tage für noch
erreichbare und 30 Tage für nicht mehr erreichbare Einträge. Der Fehler sitzt
also nicht darin, reset --hard benutzt zu haben, sondern darin, danach nicht
git reflog einzutippen, sondern in Foren nach Datenrettungswerkzeugen zu
suchen. Zwei Einschränkungen bleiben trotzdem: Das Reflog ist lokal, es reist
nicht mit einem Push mit; und es protokolliert nur Referenzen, also Commits.
Was nie committet wurde, war für Git nie da – und ist nach einem harten Reset
auch wirklich weg.
Die echte, verifizierte Lösung
1000 % faktenbasiert. Jeder Befehl ist real, jeder Pfad existiert. Schritt für Schritt:
1.
Aufhören, im Repository herumzuklicken
Kein Panik-Rebase, kein weiteres Zurücksetzen, kein git gc. Die Commits sind noch da, solange niemand nachhilft. Der einzige sinnvolle nächste Befehl ist der, der zeigt, wo der Branch vorher stand.
2.
Den alten Stand im Reflog suchen
Das Reflog listet die letzten Positionen von HEAD auf, chronologisch von neu nach alt, jeweils mit Kurzhash und dem Vorgang, der dazu geführt hat – commit, rebase, reset, checkout. Der Eintrag direkt über dem verhängnisvollen Reset ist der Stand, den du zurückwillst:
git reflog
3.
Bei Bedarf gezielt den Branch nachschlagen
War nicht HEAD, sondern ein bestimmter Branch das Opfer, lässt sich dessen eigenes Reflog getrennt anzeigen. Das ist übersichtlicher als die HEAD-Liste, in der auch jeder Branch-Wechsel steht:
git reflog show main
4.
Zuerst einen Rettungszweig setzen, nicht sofort zurücksetzen
Der sichere Weg führt über einen neuen Branch auf den gefundenen Hash. Er kostet nichts, verändert den aktuellen Stand nicht und gibt dir einen zweiten Versuch, falls du den falschen Eintrag erwischt hast. Erst danach schaut man in Ruhe nach, ob es der richtige ist:
Stimmt der Inhalt, wird der aktuelle Branch auf den Hash gezogen. Achtung: git reset --hard überschreibt dabei erneut alle nicht committeten Änderungen im Arbeitsverzeichnis – vorher also entweder committen oder mit git stash beiseitelegen:
git status
git reset --hard a1b2c3d
6.
Ergebnis prüfen und den Rettungszweig aufräumen
Ein Blick in die Historie bestätigt, dass die Commits wieder am Branch hängen. Danach kann der Hilfszweig weg – aber wirklich erst danach:
git log --oneline -10
git branch -d rettung
Häufige Fragen (FAQ)
?Warum sind die Commits nach git reset --hard nicht wirklich weg?
Weil ein Reset keinen Commit löscht, sondern nur einen Zeiger verschiebt. Der Branch zeigt danach auf einen älteren Commit, die neueren hängen an keiner Referenz mehr und sind deshalb unsichtbar – aber sie liegen weiterhin in der Objektdatenbank. Git führt zusätzlich ein Protokoll darüber, wo eine Referenz vorher stand: die Reference Logs, kurz Reflogs. Laut der Git-Dokumentation halten sie fest, wann die Spitzen von Branches und anderen Referenzen im lokalen Repository aktualisiert wurden. Genau dort steht der Hash, den du suchst.
?Wie lange bleiben verlorene Commits im Reflog auffindbar?
Lange genug, um den Schreck in Ruhe zu verdauen, aber nicht ewig. Die Git-Dokumentation nennt zwei Voreinstellungen: gc.reflogExpire läuft nach 90 Tagen ab und betrifft Einträge, die noch erreichbar sind; gc.reflogExpireUnreachable läuft nach 30 Tagen ab und betrifft Einträge, die von der aktuellen Spitze aus nicht mehr erreichbar sind – also genau deinen weggeworfenen Stand. Wer den Unfall erst nach einem Vierteljahr bemerkt, hat ein anderes Problem als Git.
?Hilft das Reflog auch bei nicht committeten Änderungen?
Nein, und das ist die unangenehme Grenze. Das Reflog protokolliert Aktualisierungen von Referenzen, also Commits. Änderungen, die nur im Arbeitsverzeichnis oder im Index lagen und nie committet wurden, sind nach einem git reset --hard tatsächlich fort – es gibt kein Objekt, auf das ein Hash zeigen könnte. Die Lehre daraus ist unromantisch: lieber ein hässlicher Zwischencommit als gar keiner.
?Funktioniert der Trick auch für einen Kollegen oder auf dem Server?
Nicht direkt. Das Reflog ist laut Dokumentation ein Protokoll des lokalen Repositories und wird nicht gepusht oder geklont. Jeder Rechner hat sein eigenes. Wer den Stand also verloren hat, muss ihn in seinem eigenen Reflog suchen – oder jemanden bitten, der die Commits noch hat, sie erneut zu veröffentlichen.
Belege
Diese Seite ist gegen die folgenden Primärquellen geprüft – Hersteller, Standard oder Gesetzestext. Wer es nicht glaubt, muss es nicht: Da steht, wo es nachzulesen ist.
Der Diff markiert jede Zeile als geändert, obwohl nur ein Wort angepasst wurde? Zeilenenden. Windows und Unix streiten sich um ein unsichtbares Zeichen.
Git meldet „detached HEAD“? Du stehst nicht auf einem Branch, sondern direkt auf einem Commit — Änderungen hier gehen ohne Gegenmaßnahme leicht verloren.