git reset
Auf dieser Seite finden Sie nützliche Informationen über den git reset-Befehl, die drei Bäume von Git und praktische Beispiele.

git reset ist der wichtigste Befehl zum Rückgängigmachen von Änderungen im lokalen Repository. Je nach gewähltem Modus kann er eine Datei aus dem Staging-Bereich entfernen, gestagte Änderungen verwerfen oder einen Branch auf einen früheren Commit zurücksetzen. Da er den Zeiger des Branches umschreiben und Arbeit verwerfen kann, ist er mächtig, aber leicht zu missbrauchen.
Diese Seite erklärt die drei „Bäume", auf die git reset einwirkt, erläutert seine drei Modi (--soft, --mixed, --hard) anhand von Beispielen und zeigt, wann stattdessen git revert verwendet werden sollte.
Wann git reset verwendet werden sollte
Greifen Sie auf git reset zurück, wenn Sie lokale History oder den Staging-Bereich umschreiben möchten, die noch nicht geteilt wurden:
- Eine Datei aus dem Staging-Bereich entfernen, die versehentlich hinzugefügt wurde:
git reset <file>. - Den gesamten Staging-Bereich leeren, um den nächsten Commit von Grund auf neu aufzubauen:
git reset. - Lokale Commits und Änderungen vollständig verwerfen:
git reset --hard <commit>. - Die letzten Commits zusammenfassen oder umschreiben vor dem Pushen.
Wenn die Commits, die rückgängig gemacht werden sollen, bereits in einen gemeinsam genutzten Branch gepusht wurden, verwenden Sie stattdessen git revert — dieser erstellt einen neuen Commit, der die Änderungen umkehrt, ohne die History umzuschreiben, auf die andere Personen angewiesen sind.
Git reset und die drei Bäume
git reset hat drei Aufrufformen, die den drei internen Zustandsverwaltungssystemen von Git entsprechen, die oft als die drei Bäume von Git bezeichnet werden:
- HEAD — die Commit-History (der Snapshot, auf den Ihr Branch aktuell zeigt).
- Staging-Index — die Änderungen, die für den nächsten Commit vorgemerkt sind.
- Arbeitsverzeichnis — die Dateien auf der Festplatte in Ihrem Editor.
Wir werden uns jedes dieser Systeme der Reihe nach ansehen.
Das Arbeitsverzeichnis
Der erste Baum ist das Arbeitsverzeichnis. Es repräsentiert die Dateien im Dateisystem Ihres Computers, die Ihr Editor verändern kann. Das Arbeitsverzeichnis ist mit einem bestimmten Commit des ausgecheckten Projekts synchronisiert: Wenn ein Projekt ausgecheckt wird, extrahiert Git dekomprimierte Versionen der Repository-Dateien auf die Festplatte.
Wenn wir eine getrackte Datei bearbeiten, meldet git status sie als geänderte, nicht gestagte Änderung im Arbeitsverzeichnis:
echo 'hello git reset' > edited_file
git status
#On branch master
#Changes not staged for commit:
#(use "git add ..." to update what will be committed)
#(use "git checkout -- ..." to discard changes in working directory)
#modified: edited_fileStaging-Index
Der zweite Baum ist der Staging-Index, der die für den nächsten Commit vorgemerkten Änderungen verfolgt. Git verbirgt die internen Details des Staging-Bereichs normalerweise vor Ihnen. Sie werden ihn auch unter verschiedenen anderen Namen finden: Cache, Directory-Cache, gestagte Dateien oder Staging-Bereich.
Um den Staging-Index direkt zu untersuchen, können wir git ls-files -s verwenden, ein Debug-Werkzeug, das die gestagten Einträge zusammen mit ihren Objekt-Hashes ausgibt:
git ls-files -s
#543644 a32de29bb3c1d643328b29ae775ad8c2e48c3256 0 edited_fileCommit-History
Der dritte Baum ist die Commit-History. Der Befehl git commit nimmt den Inhalt des Staging-Index und speichert ihn als dauerhaften Snapshot in der History:
git commit -am "edit content of test_file"
#[master ab23324] edit the content of edited_file
#1 file changed, 1 insertion(+)
git status
#On branch master
#nothing to commit, working tree cleanIm obigen Beispiel sehen Sie den neuen Commit mit der Nachricht „edit content of test_file". Die Änderungen sind an die Commit-History angehängt. In diesem Stadium zeigt git status keine bevorstehenden Änderungen an einem der Bäume. Wenn Sie git log aufrufen, sehen Sie die Commit-History. Sobald die Änderungen durch die drei Bäume durchgeführt wurden, kann git reset verwendet werden.
Wie es funktioniert
Auf den ersten Blick hat der Befehl git reset einige Ähnlichkeiten mit git checkout, da beide auf HEAD operieren. Der Befehl git checkout arbeitet ausschließlich mit dem HEAD-Referenzzeiger, während der Befehl git reset sowohl den HEAD-Referenzzeiger als auch den aktuellen Branch-Referenzzeiger verschiebt. Die folgende Illustration hilft, das Verhalten besser zu verstehen:

Diese Illustration zeigt die Abfolge der Commits auf dem master-Branch. Wie zu sehen ist, zeigen der HEAD-Ref und der master-Branch-Ref aktuell auf Commit d. Wir werden sehen, wie sich das Bild bei git checkout b und git reset b verändert.
git checkout b
Bei der Ausführung des Befehls git checkout zeigt der master-Ref weiterhin auf Commit d. Was den HEAD-Ref betrifft, wurde er verschoben und zeigt nun auf Commit b. Als Ergebnis befindet sich das Repository nun im Zustand „detached HEAD".

git reset b
Der Befehl git reset verschiebt sowohl HEAD als auch den aktuellen Branch-Ref auf den angegebenen Commit. Er kann auch den Zustand des Staging-Index und des Arbeitsverzeichnisses ändern. Drei Kommandozeilenoptionen — --soft, --mixed und --hard — steuern, wie weit dieser Reset reicht:

Hauptoptionen
Standardmäßig wird git reset mit den Argumenten --mixed und HEAD ausgeführt. Das Aufrufen von git reset entspricht also git reset --mixed HEAD. HEAD ist hier der Ziel-Commit — Sie können ihn durch eine beliebige Commit-Referenz ersetzen, z. B. einen SHA-1-Hash (git reset 0a1b2c3) oder einen relativen Zeiger (git reset HEAD~2).
Die folgende Tabelle zeigt, welche Bäume jeder Modus beeinflusst:
| Modus | Commit-History (HEAD) | Staging-Index | Arbeitsverzeichnis |
|---|---|---|---|
--soft | verschoben | unverändert | unverändert |
--mixed (Standard) | verschoben | auf Ziel zurückgesetzt | unverändert |
--hard | verschoben | auf Ziel zurückgesetzt | auf Ziel zurückgesetzt (Änderungen verloren) |
Eine hilfreiche Eselsbrücke: --soft lässt Ihre Änderungen gestagt, --mixed lässt sie als nicht gestagte Bearbeitungen und --hard verwirft sie vollständig.

--hard
--hard ist die mächtigste und gefährlichste Option. Sie verschiebt den Commit-History-Ref auf den Ziel-Commit und zwingt dann den Staging-Index und das Arbeitsverzeichnis, mit diesem Commit übereinzustimmen. Alle ausstehenden Änderungen im Staging-Index und im Arbeitsverzeichnis werden verworfen — und dieser Verlust kann nicht mit git reset rückgängig gemacht werden.
Warnung:
--hardlöscht nicht committete Arbeit dauerhaft. Führen Sie zuerstgit statusaus, um zu überprüfen, was Sie verlieren werden.
Um dies zu demonstrieren, erstellen wir zunächst einige ausstehende Änderungen:
echo 'test content' > test_file
git add test_file
echo 'modified content' >> edited_fileEine neue Datei namens test_file wurde erstellt und gestagt, und der Inhalt von edited_file wurde im Arbeitsverzeichnis geändert. Überprüfen wir den Zustand des Repositorys mit dem Befehl git status:
git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#new file: test_file
#Changes not staged for commit:
#(use "git add ..." to update what will be committed)
#(use "git checkout -- ..." to discard changes in working directory)
#modified: edited_fileEs gibt nun ausstehende Änderungen in zwei Bäumen: Der Staging-Index enthält die neue test_file, und das Arbeitsverzeichnis enthält die Änderungen an edited_file. Schauen wir uns den Zustand des Staging-Index an:
git ls-files -s
#123126 7a32454a5477b1bf4765946147c49509a431f963 0 test_file
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_fileDie test_file wurde zum Index hinzugefügt. Die edited_file wurde geändert, aber der SHA des Staging-Index (d7d77c1b04b5edd5acfc85de0b592449e5303770) bleibt gleich. Diese Änderungen befinden sich im Arbeitsverzeichnis. Sie wurden nicht in den Staging-Index übertragen, da wir den Befehl git add nicht ausgeführt haben. Nun führen wir git reset --hard aus und überprüfen den neuen Zustand des Repositorys:
git reset --hard
#HEAD is now at ab23324 update content of edited_file
git status
#On branch master
#nothing to commit, working tree clean
git ls-files -s
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_fileDie Option --hard hat einen „Hard Reset" durchgeführt. Git zeigt an, dass HEAD auf den letzten Commit ab23324 zeigt. Dann wird der Zustand des Repos mit git status geprüft. Git zeigt an, dass es keine ausstehenden Änderungen gibt. Der Staging-Index wurde auf den Zustand vor dem Hinzufügen der test_file zurückgesetzt. Die Änderungen an edited_file und das Hinzufügen von test_file wurden gelöscht. Dieser Verlust kann nicht rückgängig gemacht werden.
--mixed
--mixed ist der Standardmodus. Er verschiebt die Ref-Zeiger und setzt den Staging-Index auf den Ziel-Commit zurück, lässt das Arbeitsverzeichnis jedoch unberührt. Die Änderungen, die aus dem Index entfernt wurden, erscheinen wieder als Änderungen im Arbeitsverzeichnis, sodass nichts verloren geht — Sie haben lediglich die Möglichkeit, sie erneut zu stagen.
echo 'new file content' > test_file
git add test_file
echo 'append content' >> edited_file
git add edited_file
git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#new file: test_file
#modified: edited_file
git ls-files -s
#123126 6a32154a5477b1bf4765946147c49509a4323d32 0 test_file
#123126 3c3262db063f9e9426901092c00a3394b4bd3445 0 edited_fileIm obigen Beispiel wurde test_file hinzugefügt und der Inhalt von edited_file geändert, wobei beide Änderungen mit git add in den Staging-Index übertragen wurden. Mit diesem Zustand des Repositorys ist es an der Zeit, git reset aufzurufen:
git reset --mixed
git status
#On branch master
#Changes not staged for commit:
#(use "git add ..." to update what will be committed)
#(use "git checkout -- ..." to discard changes in working directory)
#modified: edited_file
#Untracked files:
#(use "git add ..." to include in what will be committed)
#test_file
#no changes added to commit (use "git add" and/or "git commit -a")
git ls-files -s
#123126 6c423c1b04b5edd5acfc85de0b592449e5303773 0 edited_file--mixed ist der Standardmodus und hat denselben Effekt wie git reset. git status zeigt, dass es Änderungen an edited_file gibt und dass test_file eine ungetrackte Datei ist. Das ist genau das --mixed-Verhalten. Der Staging-Index wurde zurückgesetzt und die ausstehenden Änderungen wurden in das Arbeitsverzeichnis verschoben.
--soft
Das Argument --soft verschiebt die Ref-Zeiger und hört dort auf. Es berührt weder den Staging-Index noch das Arbeitsverzeichnis, sodass alles, was committet war, gestagt bleibt und erneut committet werden kann. Dies ist der Modus, den Sie verwenden möchten, wenn Sie mehrere Commits zu einem zusammenfassen.
git reset --soft
git status
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#modified: edited_file
git ls-files -s
#123126 32a252710639e5da6b515416fd779d0741e4561a 0 edited_fileEin Soft Reset verschiebt nur die Commit-History. Standardmäßig zielt er auf HEAD. Erstellen wir einen neuen Commit und versuchen dann einen --soft-Reset mit einem anderen Ziel-Commit als HEAD:
git commit -m "add changes to edited_file"Unser Repository hat nun drei Commits. Um den ersten zu finden, überprüfen wir seine ID in der Ausgabe von git log:
git log
#commit 62e793f6941c7e0d4ad9a1345a175fe8f45cb9df
#Author: w3docs
#Date: Fri Nov 1 14:02:07 2019 -0800
#add changes to edited_file
#commit ab23324a6da9f0dec51ed16d3d8823f28e1a72a
#Author: w3docs
#Date: Fri Nov 1 11:31:58 2019 -0800
#change content of edited_file
#commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
#Author: w3docs
#Date: Thu Sep 31 18:40:29 2019 -0800
#initial commitDer unterste Eintrag ist der initiale Commit; wir verwenden seine ID als Ziel für den Soft Reset. Überprüfen wir zunächst den aktuellen Zustand des Repositorys:
git status && git ls-files -s
#On branch master
#nothing to commit, working tree clean
#123126 32a252710639e5da6b515416fd779d0741e4561a 0 edited_fileJetzt können wir zum ersten Commit zurücksetzen:
git reset --soft 780411da3b47117270c0e3a8d5dcfd11d28d04a4
git status && git ls-files -s
#On branch master
#Changes to be committed:
#(use "git reset HEAD ..." to unstage)
#modified: edited_file
#123126 32a252710639e5da6b515416fd779d0741e4561a 0 edited_fileIm obigen Beispiel haben wir einen Soft Reset durchgeführt und den kombinierten Befehl git status und git ls-files aufgerufen, der den Zustand des Repositorys ausgibt. Der Befehl git status zeigt, dass es Änderungen an edited_file gibt und hebt sie als für den nächsten Commit gestagte Änderungen hervor. Die Ausgabe von git ls-files zeigt, dass der Staging-Index unverändert geblieben ist und den SHA 32a252710639e5da6b515416fd779d0741e4561a beibehält. Untersuchen wir die Commit-History nach dem Soft Reset mit git log:
git log
#commit 780411da3b47117270c0e3a8d5dcfd11d28d04a4
#Author: w3docs
#Date: Thu Sep 31 18:40:29 2019 -0800
#initial commitDie Ausgabe zeigt nun einen einzigen Commit in der History. Wie bei allen git reset-Aufrufen setzt --soft zunächst den Commit-Baum zurück. Anders als bei den früheren --hard- und --mixed-Beispielen, die auf HEAD zielten, hat dieser Soft Reset den Commit-Baum zeitlich zurück zu einem älteren Commit verschoben — während die Arbeit selbst sicher im Staging-Index verblieb.
Der Unterschied zwischen reset und revert
git revert ist generell eine sicherere Methode zum Rückgängigmachen von Änderungen als git reset, da git reset Arbeit verlieren kann. Ein git reset löscht einen Commit nicht sofort, kann ihn aber verwaist zurücklassen — kein Branch oder Tag zeigt mehr auf ihn, sodass es keinen direkten Weg gibt, ihn zu erreichen. Git entfernt verwaiste Objekte schließlich, wenn der Garbage Collector ausgeführt wird (git gc), der standardmäßig nicht erreichbare Objekte bereinigt, die älter als etwa 90 Tage sind (Reflog-Einträge laufen nach 90 Tagen ab, oder nach 30 Tagen für nicht erreichbare). Bis dahin können Sie einen verwaisten Commit in der Regel mit dem Befehl git reflog wiederherstellen.
Der andere wesentliche Unterschied: git revert ist dafür gedacht, öffentliche, bereits geteilte Commits durch Hinzufügen eines neuen umkehrenden Commits rückgängig zu machen, während git reset dafür gedacht ist, lokale Änderungen im Arbeitsverzeichnis und Staging-Index rückgängig zu machen.
Veröffentlichte History niemals zurücksetzen
Führen Sie git reset <commit> nicht aus, wenn es Snapshots nach <commit> gibt, die bereits in ein gemeinsam genutztes Repository gepusht wurden. Sobald Sie einen Commit veröffentlichen, verlassen sich andere Entwickler darauf. Das Umschreiben oder Löschen von Commits, die Teammitglieder bereits gepullt haben, führt zu divergierenden Histories und schmerzhaften Merge-Konflikten. Verwenden Sie git reset nur für Commits, die ausschließlich in Ihrem lokalen Repository existieren. Um öffentliche Änderungen rückgängig zu machen, verwenden Sie stattdessen den Befehl git revert.
Beispiele
Eine bestimmte Datei aus dem Staging-Bereich entfernen, ohne das Arbeitsverzeichnis zu verändern — die Datei wird aus dem Staging entfernt, während Ihre Bearbeitungen erhalten bleiben:
git reset <file>Den gesamten Staging-Bereich zurücksetzen, um mit dem letzten Commit übereinzustimmen, und das Arbeitsverzeichnis unverändert lassen. Dadurch wird jede Datei aus dem Staging entfernt, ohne Änderungen zu überschreiben, sodass Sie den gestagten Snapshot von Grund auf neu aufbauen können:
git resetSowohl den Staging-Bereich als auch das Arbeitsverzeichnis zurücksetzen, um mit dem letzten Commit übereinzustimmen. Dadurch werden alle nicht committeten Änderungen im Arbeitsverzeichnis verworfen:
git reset --hardDie Branch-Spitze auf einen bestimmten Commit zurücksetzen und den Staging-Bereich entsprechend zurücksetzen, das Arbeitsverzeichnis jedoch unberührt lassen:
git reset <commit>Die aktuelle Branch-Spitze auf einen bestimmten Commit zurücksetzen und sowohl den Staging-Bereich als auch das Arbeitsverzeichnis entsprechend zurücksetzen:
git reset --hard <commit>Lokale Commits entfernen
Wie oben gezeigt, können Sie git reset verwenden, um Commits in Ihrem lokalen Repository zu löschen. Im folgenden Beispiel verschiebt git reset --hard HEAD~2 den aktuellen Branch um zwei Commits zurück und entfernt die beiden neuesten Snapshots aus der Projekthistory:
# Create a new file called `yourname.txt` and add some code to it
# Commit it to the project history
git add yourname.txt
git commit -m "Start to develop a project"
# Edit `yourname.txt` again and change some other tracked files, too
# Commit another snapshot
git commit -a -m "Continue developing"
# Scrap the project and remove the related commits
git reset --hard HEAD~2Dateien aus dem Staging entfernen
Eine sehr häufige Verwendung von git reset ist die Feinabstimmung, was in den nächsten Commit einfließt. Im folgenden Beispiel haben wir zwei Dateien, task.txt und index.txt, die beide gestagt wurden. git reset ermöglicht es uns, die Änderungen aus dem Staging zu entfernen, die nicht in den nächsten Commit gehören, sodass jede Datei separat committet werden kann:
# Edit task.txt and index.txt
# Stage everything in the current directory
git add .
# Realize that the changes in task.txt and index.txt
# should be committed in different snapshots
# Unstage index.txt
git reset index.txt
# Commit only task.txt
git commit -m "Edit task.txt"
# Commit index.txt in a separate snapshot
git add index.txt
git commit -m "Edit index.txt"