Verwendung des Reflogs zur Wiederherstellung verlorener Commits

Avatar of Tobias Günther
Tobias Günther am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

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.

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
Screenshot of a Terminal with a light yellow background and black text. The content shows the output from the git config gc.reflogExpire 180.days.ago command.
Die Konfigurationsdatei des Repositories (.git/config) enthält nun die Variable reflogExpire mit dem Wert 180.days.ago

Alternativ 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

Screenshot of the Tower application interface. On the left is a navigation with the History item selected. In the center panel is a visual outline of the commit history showing the avatars of people who made the commits. The second commit is selected and on the right is a panel showing more detail about the commit, including the author, date, committer, refs, hashes, and changed files.

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
Screenshot of the Tower application interface. The master branch is selected in the right navigation, the first commit is selected in the center panel, and the detail for that commit is displayed in the right panel. The commits in the center panel are clean and linear without any additional commits or branches.

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.

Screenshot of an open Terminal window with a light yellow background. The text is mainly black, but some words are highlighted in red, light blue and bright green. The top line is the git reset --hard 2b504bee command. The second line says the head is now at that commit ID. The third line is the git reflog command, which outputs the history.

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.

A screenshot of the terminal with a light yellow background and the output for git reflog in it, on top of a screenshot of the Tower application window, showing the updated commit history following the command.

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.

Illustration showing the commit history flow of a feature/login branch with ID C2 being deleted from a C2 branch that is off the master branch. Beside the diagram is a list of the steps taken to deleted the branch, ending with step 4: you panic next to a screaming emoji.

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

Screenshot of the Tower app interface showing the login branch selected in the left panel, the commit history of that branch in the center panel with the first commit selected and highlighted in blue, then details for the commit in the right panel, including the author, date, refs, cases, and modified files.

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.

Screenshot of an open Terminal window with a light yellow background and mostly black text, though the branch and committer names are highlighted in bright green. The first command is git status, the second is git checkout master, the third is git branch -vv, the fourth is git branch -D feature/login, and the last command is git branch -vv.

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.

Screenshot of the Tower application interface. The feature/login branch is selected in the left panel, the commit history for the branch is in the center panel with the first commit selected, and the left panel displays more information ab out the commit, including the author, date, refs, hashes, and modified files.

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!