Layer 8Ehrlicher Tech-Support

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. 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. 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. 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. 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:

    git branch rettung a1b2c3d
    git log --oneline -5 rettung
    
  5. 5.

    Den Branch auf den geretteten Stand zurückholen

    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. 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.

  1. [1]

Zuletzt geprüft am . Dokumentation altert – ein Datum daneben ist der einzige ehrliche Umgang damit.

Auch zu finden unter

Verwandte Fehler

SWLästigNot possible to fast-forward, aborting.

git pull: Not possible to fast-forward, aborting

git pull bricht ab, sobald eigener und entfernter Zweig auseinandergelaufen sind. Laut Git 2.55 ist --ff-only die Voreinstellung, nicht der Merge.

SWLästig! [rejected] (non-fast-forward)

git push rejected: non-fast-forward beheben

git push wird mit '! [rejected] non-fast-forward' abgelehnt? Die Remote hat Commits, die dir fehlen. So holst du sie sauber nach und pushst gefahrlos.

SWLästigdetached HEAD

Git: detached HEAD state

Git meldet „detached HEAD“? Du stehst nicht auf einem Branch, sondern direkt auf einem Commit — Änderungen hier gehen ohne Gegenmaßnahme leicht verloren.