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:
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 main to git_reflog
9a4491f HEAD@{3}: checkout: moving from Git_Config to main
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 main@{0} main@{1.day.ago}
In diesem Beispiel wird der aktuelle Main-Branch mit dem Main 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 main@{0}
gleichbedeutend mit dem Befehl:
git reflog show main@{0}
Außerdem ist git reflog show
ein Alias für git log -g --abbrev-commit --pretty=oneline
. Mit der Ausführung von git reflog show
wird das Protokoll für die übergebene
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 Main-Branch durch. Dies geschieht mit dem folgenden Befehl:
git rebase -i origin/main
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/main 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.
Zusammenfassung
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.