git reflog

In diesem Artikel wird der Befehl git reflog im Detail erläutert. Git verfolgt die Updates an den Branch-Spitzen mit einem Mechanismus namens Reflog (kurz für reference log – Referenzprotokoll). Viele Git-Befehle akzeptieren einen Parameter zur Bestimmung einer Referenz oder "Ref" als Pointer zu einem Commit. Einige gebräuchliche Beispiele:

  • git checkout
  • git reset
  • git merge

Reflogs verfolgen, wann Git-Refs im lokalen Repository aktualisiert wurden. Neben den Reflogs der Branch-Spitzen wird ein spezieller Reflog für den Git Stash gepflegt. Reflogs werden in Verzeichnissen unter dem .git-Verzeichnis des lokalen Repositorys gespeichert. git reflog-Verzeichnisse befinden sich unter .git/logs/refs/heads/., .git/logs/HEAD und .git/logs/refs/stash, wenn git stash für das Repository verwendet wurde.

Wir haben git reflog auf der Seite Umarbeiten von Verläufen bereits oberflächlich angesprochen. In diesem Artikel behandeln wir folgende Themen: die erweiterten Konfigurationsoptionen von git reflog, häufige Anwendungsfälle und Fallstricke von git reflog, das Rückgängigmachen von Änderungen mit git reflog und mehr.

Grundlegende Nutzung

Der einfachste Reflog-Use Case:

git reflog

Dies ist im Prinzip eine Abkürzung von:

git reflog show HEAD

Dies gibt den HEAD-Reflog zurück. Die Ausgabe sieht ungefähr so aus:

eff544f HEAD@{0}: commit: migrate existing content
bf871fd HEAD@{1}: commit: Add Git Reflog outline
9a4491f HEAD@{2}: checkout: moving from master to git_reflog
9a4491f HEAD@{3}: checkout: moving from Git_Config to master
39b159a HEAD@{4}: commit: expand on git context
9b3aa71 HEAD@{5}: commit: more color clarification
f34388b HEAD@{6}: commit: expand on color support
9962aed HEAD@{7}: commit: a git editor -> the Git editor

Auf der Seite Umarbeiten von Verläufen findest du ein weiteres Beispiel für eine gebräuchliche Verwendung von "git reflog".

Reflog-Referenzen

In den Standardeinstellungen gibt git reflog das Reflog der HEAD-Referenz zurück. HEAD ist eine symbolische Referenz zum aktuell aktiven Branch. Reflogs sind auch für anderen Referenzen verfügbar. Der Syntax für den Zugriff auf eine Git-Referenz lautet name@{qualifier}. Neben den HEAD-Referenzen können auch andere Branches, Tags, Remotes und der Git Stash referenziert werden.

Wenn du folgenden Befehl ausführst, erhältst du einen vollständigen Reflog aller Referenzen:

 git reflog show --all

Zur Anzeige des Reflogs für einen bestimmten Branch fügst du git reflog show den Branch-Namen hinzu.

git reflog show otherbranch
9a4491f otherbranch@{0}: commit: seperate articles into branch PRs
35aee4a otherbranch{1}: commit (initial): initial commit add git-init and setting-up-a-repo docs

Das Ausführen dieses Beispiels gibt einen Reflog für den Branch otherbranch zurück. Im folgenden Beispiel nehmen wir an, du hast zuvor einige Änderungen mit dem Befehl git stash beiseitegelegt.

git reflog stash
0d44de3 stash@{0}: WIP on git_reflog: c492574 flesh out intro

Dies gibt ein Reflog für den Git Stash zurück. Die angezeigten Referenz-Pointers können an andere Git-Befehle angefügt werden:

git diff stash@{0} otherbranch@{0}

Wenn dieser Beispielcode ausgeführt wird, wird eine Git diff-Ausgabe angezeigt, in der die stash@{0}-Änderungen mit der otherbranch@{0}-Referenz verglichen werden.

Reflogs für einen bestimmten Zeitpunkt

Jedes Reflog ist mit einer Zeitmarke versehen. Diese Zeitmarken können in einer Git Referenz-Pointer-Syntax als qualifier-Token genutzt werden. Auf diese Weise können Git-Reflogs nach Zeitpunkten gefiltert werden. Im Folgenden siehst du einige Beispiele verfügbarer Zeit-Qualifier:

  • 1.minute.ago
  • 1.hour.ago
  • 1.day.ago
  • yesterday
  • 1.week.ago
  • 1.month.ago
  • 1.year.ago
  • 2011-05-17.09:00:00
     

Zeit-Qualifier können kombiniert werden (z. B. 1.day.2.hours.ago) und auch Pluralformen werden akzeptiert (z. B. 5.minutes.ago).

Zeit-Qualifier können an andere Git-Befehle angefügt werden.

 git diff master@{0} master@{1.day.ago}

In diesem Beispiel wird der aktuelle Master Branch mit dem Master von vor einem Tag verglichen. Dieses Beispiel ist äußerst hilfreich, wenn du wissen möchtest, was sich innerhalb eines bestimmten Zeitraums geändert hat.

Unterbefehle und Konfigurationsoptionen

git reflog akzeptiert einige zusätzliche Argumente, die als Unterbefehle betrachtet werden.

Show - git reflog show

show wird standardmäßig impliziert. Beispielsweise ist der Befehl:

git reflog master@{0}

gleichbedeutend mit dem Befehl:

git reflog show master@{0}

Außerdem ist git reflog show ein Alias für git log -g --abbrev-commit --pretty=oneline. Mit git reflog show wird das Protokoll für die angegebene <refid> angezeigt.

Expire - git reflog expire

Der Unterbefehl "expire" bereinigt alte oder unerreichbare Reflog-Einträge. Doch beim expire-Unterbefehl können potenziell Daten verloren gehen. Deshalb wird dieser Unterbefehl normalerweise nicht von Endbenutzern, sondern von Git intern verwendet. Durch das Hinzufügen der Option -n oder --dry-run zu git reflog expire wird ein "Probelauf" durchgeführt, der zurückgibt, welche Reflog-Einträge zum Pruning markiert wurden, ohne sie tatsächlich zu löschen.

Standardmäßig ist das Reflog-Ablaufdatum auf 90 Tage gesetzt. Das Ablaufdatum kann individuell festgelegt werden, indem der Zusatz --expire=time an git reflog expire angefügt wird oder indem ein Git Konfigurationsname für gc.reflogExpire eingerichtet wird.

Delete - git reflog delete

Der Unterbefehl delete erklärt sich eigentlich von selbst: Der angegebene Reflog-Eintrag wird gelöscht. Wie expire kann auch delete potenziell zu Datenverlusten führen und wird normalerweise nicht von Endbenutzern verwendet.

Wiederherstellen verlorener Commits

In Git geht nichts wirklich verloren, nicht einmal beim Umarbeiten eines Verlaufs mit Vorgängen wie Rebasing oder Commit-Änderungen. Im nächsten Beispiel nehmen wir an, wir haben Änderungen an unserem Repository vorgenommen. Unsere Ausgabe für git log --pretty=oneline sieht folgendermaßen aus:

338fbcb41de10f7f2e54095f5649426cb4bf2458 extended content
1e63ceab309da94256db8fb1f35b1678fb74abd4 bunch of content
c49257493a95185997c87e0bc3a9481715270086 flesh out intro
eff544f986d270d7f97c77618314a06f024c7916 migrate existing content
bf871fd762d8ef2e146d7f0226e81a92f91975ad Add Git Reflog outline
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit add git-init and setting-up-a-repo docs

Wir committen diese Änderungen und führen Folgendes aus:

#make changes to HEAD
git commit -am "some WIP changes"

Nachdem der neue Commit hinzugekommen ist, sieht das Protokoll folgendermaßen aus:

37656e19d4e4f1a9b419f57850c8f1974f871b07 some WIP changes
338fbcb41de10f7f2e54095f5649426cb4bf2458 extended content
1e63ceab309da94256db8fb1f35b1678fb74abd4 bunch of content
c49257493a95185997c87e0bc3a9481715270086 flesh out intro
eff544f986d270d7f97c77618314a06f024c7916 migrate existing content
bf871fd762d8ef2e146d7f0226e81a92f91975ad Add Git Reflog outline
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit add git-init and setting-up-a-repo docs

Nun führen wir ein interaktives Rebasing mit dem Master Branch durch. Dies geschieht mit dem folgenden Befehl:

git rebase -i origin/master

Während des Rebasings markieren wir mit dem Rebase-Unterbefehl s Commits für einen Squash. Außerdem squashen wir einige Commits in den neuesten "some WIP changes"-Commit.

Da wir Commits gesquasht haben sieht die Ausgabe von git log nun folgendermaßen aus:

40dhsoi37656e19d4e4f1a9b419f57850ch87dah987698hs some WIP changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit add git-init and setting-up-a-repo docs

Wenn wir uns git log jetzt ansehen, sieht es so aus, als ob keine weiteren Commit für einen Squash markiert sind. Wie gehen wir vor, wenn wir eine Aktion für einen der gesquashten Commits durchführen möchten? Vielleicht sollen seine Änderungen aus dem Verlauf entfernt werden? Hierzu kann das Reflog genutzt werden.

git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/master
37656e1 HEAD@{2}: commit: some WIP changes

Wir sehen hier, dass es Reflog-Einträge für den Beginn und das Ende für rebase gibt, und vor diesen steht unser "some WIP changes"-Commit. Wir können die Reflog-Referenz an git reset anfügen und auf einen Commit zurücksetzen, der vor dem Rebasing vorhanden war.

git reset HEAD@{2}

Das Ausführen von "git reset" verschiebt HEAD zu dem Commit, dem der "some WIP changes"-Commit hinzugefügt wurde, und stellt im Wesentlichen die anderen gesquashten Commits wieder her.

Summary

In diesem Tutorial haben wir den Befehl git reflog behandelt. Dabei wurden insbesondere die folgenden Themen besprochen:

  • Ansehen des Reflogs für bestimmte Branches
  • Rückgängigmachen einer Git Rebase mithilfe des Reflogs
  • Angeben und Ansehen von Reflog-Einträgen für einen bestimmten Zeitpunkt

Wir haben kurz erwähnt, dass git reflog mit anderen Befehlen wie git checkout, git reset und git merge kombiniert werden kann. Hierzu erfährst du auf den jeweiligen Seiten mehr. Wenn du noch tiefer in das Thema "Referenzen und das Reflog" eintauchen möchtest, lies hier weiter.
 

Du möchtest mit Git arbeiten?

Sieh dir dieses interaktive Tutorial an.

Jetzt loslegen