Dieser Artikel ist Teil unserer Serie „Advanced Git“. Folgen Sie uns unbedingt auf Twitter oder melden Sie sich für unseren Newsletter an, um über zukünftige Artikel informiert zu werden!
Das „Reflog“ ist eines der weniger bekannten Features von Git – aber eines, das äußerst hilfreich sein kann. Manche Leute bezeichnen es als „Sicherheitsnetz“, während ich es gerne als „Tagebuch“ von Git bezeichne. Das liegt daran, dass Git es verwendet, um ein Journal über jede Bewegung des HEAD-Pointers zu führen (d. h. jedes Mal, wenn Sie committen, mergen, rebasen, cherry-picken, zurücksetzen usw.). Git protokolliert Ihre Aktionen im Reflog, was es zu einem wertvollen Logbuch und einem guten Ausgangspunkt macht, wenn etwas schiefgelaufen ist.
In diesem letzten Teil unserer „Advanced Git“-Serie erkläre ich die Unterschiede zwischen git log und git reflog und zeige Ihnen, wie Sie das Reflog verwenden können, um gelöschte Commits sowie gelöschte Branches wiederherzustellen.
Fortgeschrittene Git-Serie
- Teil 1: Den perfekten Commit in Git erstellen
- Teil 2: Branching-Strategien in Git
- Teil 3: Bessere Zusammenarbeit mit Pull Requests
- Teil 4: Merge-Konflikte
- Teil 5: Rebase vs. Merge
- Teil 6: Interaktiver Rebase
- Teil 7: Cherry-Picking von Commits in Git
- Teil 8: Verwendung des Reflogs zur Wiederherstellung verlorener Commits (Sie sind hier!)
git log oder git reflog: Was ist der Unterschied?
In früheren Artikeln habe ich empfohlen, den Befehl git log zu verwenden, um vergangene Ereignisse zu inspizieren und sich die Commit-Historie anzusehen, und genau das tut er auch. Er zeigt den aktuellen HEAD und seine Vorfahren, d. h. seinen Elternteil, den nächsten Elternteil in der Reihe usw. Der Log geht die gesamte Commit-Historie zurück, indem er rekursiv den Elternteil jedes Commits ausgibt. Er ist Teil des Repositories, was bedeutet, dass er nach dem Pushen, Fetchen oder Pullen repliziert wird.
git reflog hingegen ist eine private und arbeitsbereichsbezogene Aufzeichnung. Er durchläuft nicht die Liste der Vorfahren. Stattdessen zeigt er eine geordnete Liste aller Commits an, auf die HEAD in der Vergangenheit gezeigt hat. Deshalb können Sie ihn als eine Art „Rückgängig-Historie“ betrachten, wie Sie sie vielleicht in Textverarbeitungsprogrammen, Texteditoren usw. sehen.
Diese lokale Aufzeichnung ist technisch gesehen kein Teil des Repositories und wird getrennt von den Commits gespeichert. Das Reflog ist eine Datei in .git/logs/refs/heads/ und verfolgt die lokalen Commits für jeden Branch. Das Tagebuch von Git wird normalerweise nach 90 Tagen bereinigt (das ist die Standardeinstellung), aber Sie können das Ablaufdatum des Reflogs einfach anpassen. Um die Anzahl der Tage auf 180 zu ändern, geben Sie einfach den folgenden Befehl ein
$ git config gc.reflogExpire 180.days.ago

.git/config) enthält nun die Variable reflogExpire mit dem Wert 180.days.agoAlternativ können Sie entscheiden, dass Ihr Reflog niemals verfallen soll
$ git config gc.reflogExpire never
Tipp: Denken Sie daran, dass Git zwischen der Konfigurationsdatei des Repositories (.git/config), der globalen benutzerspezifischen Konfiguration ($HOME/.gitconfig) und den systemweiten Einstellungen (/etc/gitconfig) unterscheidet. Um das Ablaufdatum des Reflogs für den Benutzer oder das System anzupassen, fügen Sie den Parameter --system oder --global zu den oben gezeigten Befehlen hinzu.
Genug theoretischer Hintergrund – lassen Sie mich Ihnen zeigen, wie Sie mit git reflog Fehler korrigieren können.
Wiederherstellung gelöschter Commits
Stellen Sie sich folgendes Szenario vor: Nachdem Sie Ihre Commit-Historie durchgesehen haben, entscheiden Sie sich, die letzten beiden Commits zu entfernen. Sie führen mutig einen git reset aus, die beiden Commits verschwinden aus der Commit-Historie… und eine Weile später stellen Sie fest, dass dies ein Fehler war. Sie haben gerade wertvolle Änderungen verloren und geraten in Panik!

Müssen Sie wirklich wieder von vorne anfangen? Nein. Mit anderen Worten: Bleiben Sie ruhig und benutzen Sie git reflog!
Lassen Sie uns also Dinge durcheinanderbringen und diesen Fehler in Echtzeit nachstellen. Das nächste Bild zeigt unsere ursprüngliche Commit-Historie in Tower, einem grafischen Git-Client

Wir möchten zwei Commits loswerden und den Commit „Change headlines for about and imprint“ (ID: 2b504bee) zu unserer letzten Revision im master-Branch machen. Alles, was wir tun müssen, ist, die Hash-ID in die Zwischenablage zu kopieren und dann git reset in der Befehlszeile zu verwenden und diesen Hash einzugeben.
$ git reset --hard 2b504bee

Voilà. Die Commits sind verschwunden. Nehmen wir nun an, das war ein Fehler, und schauen wir uns das Reflog an, um die verlorenen Daten wiederherzustellen. Geben Sie git reflog ein, um das Journal in Ihrem Terminal anzuzeigen.

Sie werden feststellen, dass alle Einträge chronologisch geordnet sind. Das bedeutet: Die neuesten – die aktuellsten – Commits stehen ganz oben. Und wenn Sie genau hinschauen, werden Sie die fatale git reset-Aktion von vor ein paar Minuten ganz oben bemerken.
Das Tagebuch scheint zu funktionieren – das ist eine gute Nachricht. Lassen Sie es uns also verwenden, um die letzte Aktion rückgängig zu machen und den Zustand vor dem Reset-Befehl wiederherzustellen. Kopieren Sie wie zuvor die Hash-ID (die in diesem speziellen Beispiel e5b19e4 lautet) in die Zwischenablage. Sie könnten erneut git reset verwenden, was völlig gültig ist. Aber in diesem Fall erstelle ich einen neuen Branch basierend auf dem alten Zustand.
$ git branch happy-ending e5b19e4
Werfen wir einen Blick auf unseren grafischen Git-Client.

Wie Sie sehen können, wurde der neue Branch happy-ending erstellt und er enthält die Commits, die wir zuvor gelöscht haben – großartig, nichts ist verloren!
Betrachten wir ein weiteres Beispiel und verwenden wir das Reflog, um einen gesamten Branch wiederherzustellen.
Wiederherstellung gelöschter Branches
Das nächste Beispiel ähnelt unserem ersten Szenario: Wir werden etwas löschen – diesmal ist es ein ganzer Branch, der verschwinden soll. Vielleicht hat Ihnen Ihr Kunde oder Ihr Teamleiter gesagt, Sie sollen einen Feature-Branch entfernen, vielleicht war es Ihre eigene Idee, aufzuräumen. Um die Sache schlimmer zu machen, ist ein Commit (C3 auf dem Bild) in keinem der anderen Branches enthalten, sodass Sie definitiv Daten verlieren werden.

Lassen Sie uns das tatsächlich tun und dann den Branch später wiederherstellen.

Bevor Sie den Branch feature/login löschen können, müssen Sie sich von ihm entfernen. (Wie Sie im Screenshot sehen können, ist es der aktuelle HEAD-Branch, und Sie können den HEAD-Branch in Git nicht löschen.) Also wechseln wir zu einem anderen Branch (zu master) und löschen dann feature/login.

Okay… nun sagen wir, unser Kunde oder Teamleiter hat einen Sinneswandel gehabt. Der Branch feature/login (einschließlich seiner Commits) wird doch noch benötigt. Was sollen wir tun?
Werfen wir einen Blick in das Tagebuch von Git.
$ git reflog
776f8ca (HEAD -> master) HEAD@{0}: checkout: moving from feature/login to master
b1c249b (feature/login) HEAD@{1}: checkout: moving from master to feature/login
[...]
Es stellt sich heraus, dass wir wieder Glück haben. Der letzte Eintrag zeigt unseren Wechsel von feature/login zu master. Versuchen wir, zu dem Zustand davor zurückzukehren und kopieren die Hash-ID b1c249b in die Zwischenablage. Als Nächstes erstellen wir einen Branch namens feature/login, der auf dem gewünschten Zustand basiert.
$ git branch feature/login b1c249b
$ git branch -vv
feature/login b1c249b Change Imprint page title
* master 776f8ca Change about title and delete error page
Prima – der Branch ist wieder lebendig und enthält auch den wertvollen Commit, den wir verloren glaubten.

Wenn Sie Git in einer Desktop-GUI wie Tower verwenden, können Sie einfach CMD+Z drücken, um Ihre letzte Aktion rückgängig zu machen, genau wie in einem Texteditor oder Textverarbeitungsprogramm, wenn Sie einen Tippfehler machen.
Bleiben Sie ruhig und behalten Sie den Überblick
Das Reflog von Git kann wirklich eine Rettung sein! Wie Sie sehen können, ist es ziemlich einfach, verlorene Commits oder sogar ganze Branches aus dem Grab zurückzuholen. Was Sie tun müssen, ist, die richtige Hash-ID im Reflog zu finden – der Rest ist ein Kinderspiel.
Wenn Sie tiefer in fortgeschrittene Git-Tools eintauchen möchten, können Sie sich gerne mein (kostenloses!) „Advanced Git Kit“ ansehen: Es ist eine Sammlung kurzer Videos zu Themen wie Branching-Strategien, Interactive Rebase, Reflog, Submodules und vieles mehr.
Dies war der letzte Teil unserer Serie über „Advanced Git“ hier bei CSS-Tricks. Ich hoffe, Ihnen haben die Artikel gefallen. Viel Spaß beim Hacking!
Fortgeschrittene Git-Serie
- Teil 1: Den perfekten Commit in Git erstellen
- Teil 2: Branching-Strategien in Git
- Teil 3: Bessere Zusammenarbeit mit Pull Requests
- Teil 4: Merge-Konflikte
- Teil 5: Rebase vs. Merge
- Teil 6: Interaktiver Rebase
- Teil 7: Cherry-Picking von Commits in Git
- Teil 8: Verwendung des Reflogs zur Wiederherstellung verlorener Commits (Sie sind hier!)
Tolle Artikelreihe. Ich schätze es besonders, dass Sie alle Beispiele auf der CLI (Command Line Interface) aufgenommen haben, anstatt den Standpunkt einzunehmen, alles in der GUI (in diesem Fall Tower) zu machen. Hoffentlich werden die Leute das Beste aus beiden Welten mitnehmen, weniger Angst vor der CLI haben und Tower kaufen.
Vielen Dank, Piotr!
Tolle Artikel! Hat mich als Teamentwicklungsanfänger sehr inspiriert!