Close

Resetting, checking out & reverting


The git reset, git checkout, and git revert commands are some of the most useful tools in your Git toolbox. They all let you undo some kind of change in your repository, and the first two commands can be used to manipulate either commits or individual files.

Das sie sehr ähnlich sind, kommt es bei der Auswahl des richtigen Befehls für das jeweilige Entwicklungsszenario leicht zu Verwechslungen. In diesem Artikel vergleichen wir die geläufigsten Konfigurationen von git reset, git checkout und git revert. Jetzt kannst du hoffentlich mit all diesen Befehlen sicher durch dein Repository navigieren.

Die drei Bäume von Git

It helps to think about each command in terms of their effect on the three state management mechanisms of a Git repository: the working directory, the staged snapshot, and the commit history. These components are sometimes known as "The three trees" of Git. We explore the three trees in depth on the git reset page. Keep these mechanisms in mind as you read through this article.

Beim Checkout wird der HEAD-Ref-Pointer zu einem bestimmten Commit verschoben. Dieser Vorgang wird im folgenden Beispiel veranschaulicht:

Verschieben des HEAD-Ref-Pointers zu einem bestimmten Commit
Datenbanken
Zugehöriges Material

Verschieben eines vollständigen Git-Repositorys

Bitbucket-Logo
Lösung anzeigen

Git kennenlernen mit Bitbucket Cloud

In diesem Beispiel sehen wir eine Reihe an Commits im main-Branch. Die HEAD-Referenz und die main-Branch-Referenz verweisen derzeit auf Commit d. Führen wir nun git checkout b aus.

Sequence of commits on the main branch

Das ist ein Update am "Commit-Verlauf"-Baum. Der Befehl git checkout ist auf Commit- oder Dateiebene anwendbar. Bei einem Checkout auf Dateiebene wird der Inhalt der Datei mit dem des entsprechenden Commit aktualisiert.

Beim Rückgängigmachen mit "revert" wird ein neuer Commit erstellt, der den angegebenen Commit umkehrt. git revert ist nur auf Commit-Ebene anwendbar und funktioniert nicht auf Dateiebene.

Beim Zurücksetzen mit "reset" werden die "drei Bäume" auf den Zustand des Repositorys zurückgesetzt, der einem bestimmten Commit entspricht. Für die drei Bäume gibt es drei verschiedene Arten des Zurücksetzens.

"Checkout" und "reset" werden normalerweise verwendet, um lokale oder private Änderungen rückgängig zu machen. Dadurch wird der Verlauf eines Repositorys verändert, was beim Pushen zu gemeinsam genutzten Remote-Repositorys zu Konflikten führen kann. Das Rückgängigmachen mit "revert" gilt als sichere Methode zum Zurücksetzen öffentlicher Änderungen, da ein neuer Verlauf erstellt wird, der remote gemeinsam genutzt werden kann. Der ursprüngliche Verlauf, der eventuell von Mitgliedern des Remote-Teams genutzt wird, wird so nicht überschrieben.

Git reset vs revert vs checkout reference


In der folgenden Tabelle werden die häufigsten Anwendungen für diese Befehle zusammengefasst. Im Laufe deiner Arbeit mit Git wirst du sicherlich ein paar dieser Befehle gebrauchen können. Halte diesen Überblick also stets griffbereit.

Befehl

Umfang

Häufige Anwendungsfälle

git reset

Umfang

Commit-Ebene

Häufige Anwendungsfälle

Discard commits in a private branch or throw away uncommitted changes

git reset

Umfang

Dateiebene

Häufige Anwendungsfälle

Entfernen einer Datei aus der Staging-Umgebung

git checkout

Umfang

Commit-Ebene

Häufige Anwendungsfälle

Wechseln zwischen Branches oder Ansehen alter Snapshots

git checkout

Umfang

Dateiebene

Häufige Anwendungsfälle

Verwerfen von Änderungen im Arbeitsverzeichnis

git revert

Umfang

Commit-Ebene

Häufige Anwendungsfälle

Rückgängigmachen von Commits in einem öffentlichen Branch

git revert

Umfang

Dateiebene

Häufige Anwendungsfälle

Nicht verfügbar

Commit level operations


Mit den Parametern, die du auf git reset und git checkout anwendest, legst du den jeweiligen Umfang fest. Wenn du als Parameter keinen Dateipfad angibst, wird der Befehl auf ganze Commits angewendet. Darum geht es in diesem Abschnitt. Beachte, dass es zu git revert kein Gegenstück gibt, das auf Dateiebene funktioniert.

Reset a specific commit

Auf Commit-Ebene ist das Zurücksetzen eine Möglichkeit, die Spitze eines Branch zu einem anderen Commit zu verschieben. Hiermit können Commits vom aktuellen Branch entfernt werden. Der folgende Befehl verschiebt z. B. den hotfix Branch zwei Commits zurück.

git checkout hotfix git reset HEAD~2

Die beiden Commits am Ende von hotfix sind nun verwaiste Commits, d. h. von diesem Branch losgelöst. Sie werden bei der nächsten Speicherbereinigung von Git gelöscht. Anders ausgedrückt: Damit gibst du an, dass diese Commits verworfen werden sollen. Das lässt sich wie folgt veranschaulichen:

Zurücksetzen des hotfix-Branches auf HEAD-2

Mit git reset lassen sich auf einfache Weise Änderungen rückgängig machen, die noch nicht mit anderen geteilt wurden. Dies ist der Befehl erster Wahl, wenn du mit der Arbeit an einem Feature begonnen hast und dir plötzlich denkst: "Ach, du meine Güte, was mache ich hier eigentlich? Ich sollte besser ganz von vorne anfangen."

Neben dem Verschieben des aktuellen Branch, kannst du über git reset mit den folgenden Zusätzen auch den Snapshot aus der Staging-Umgebung und/oder das Arbeitsverzeichnis ändern:

  • --soft: Der Snapshot der Staging-Umgebung und das Arbeitsverzeichnis bleiben unverändert.
  • --mixed: Der Snapshot aus der Staging-Umgebung wird zur Übereinstimmung mit dem angegebenen Commit aktualisiert, aber das Arbeitsverzeichnis bleibt unberührt. Dies ist die Standardoption.
  • --hard: Der gestagte Snapshot und das Arbeitsverzeichnis werden auf den angegebenen Commit zurückgesetzt.

It’s easier to think of these modes as defining the scope of a git reset operation. For further detailed information visit the git reset page.

Ältere Commits auschecken

Mit dem Befehl git checkout wird das Repository aktualisiert, um dem Zustand an einer bestimmten Stelle des Projektverlaufs zu entsprechen. Wenn du dabei einen Branch-Namen angibst, kannst du zwischen verschiedenen Branches wechseln.

git checkout hotfix

Der obige Befehl verschiebt den HEAD lediglich auf einen anderen Branch und aktualisiert das Arbeitsverzeichnis entsprechend. Das birgt die Gefahr, dass lokale Änderungen überschrieben werden. Deshalb zwingt dich Git, alle Änderungen im Arbeitsverzeichnis, die während des Checkouts verloren gehen, zu committen oder zu stashen. Mit git checkout werden – im Gegensatz zu git reset – Branches nicht verschoben.

Moving HEAD from main to hotfix

Du kannst beliebige Commits auch auschecken, indem du die Commit-Referenz anstelle des Branches anwendest. Das Ergebnis ist genau dasselbe wie beim Auschecken eines Branches: Die HEAD-Referenz wird zum angegebenen Commit verschoben. Der folgende Befehl zum Beispiel checkt den überübergeordneten Commit des aktuellen Commits aus:

git checkout HEAD~2
Verschieben von HEAD zu einem beliebigen Commit

Das ist nützlich, wenn du einen schnellen Blick in eine ältere Version deines Projekts werfen willst. Da jedoch keine Branch-Referenz zum aktuellen HEAD besteht, befindest du dich in einem Zustand mit losgelöstem HEAD (im Englischen "detached HEAD"). Das kann riskant sein, wenn du einen neuen Commit hinzufügen willst. Wenn du dann zu einem anderen Branch wechselst, kannst du anschließend nicht mehr zum HEAD zurückkehren. Daher solltest du immer einen neuen Branch erstellen, bevor du Commits zu einem losgelösten HEAD hinzufügst.

Undo public commits with revert

Mit "revert" machst du einen Commit rückgängig, indem ein neuer Commit erstellt wird. Das ist eine sichere Methode zum Rückgängigmachen von Änderungen, denn dabei ist ausgeschlossen, dass der Commit-Verlauf überschrieben wird. Zum Beispiel werden mit folgendem Befehl die Änderungen im zweitletzten Commit ermittelt, ein neuer Commit erstellt, der diese Änderung rückgängig macht, und der neue Commit dem bestehenden Projekt angehängt.

git checkout hotfix git revert HEAD~2

Das lässt sich wie folgt veranschaulichen:

Rückgängigmachen des zweitletzten Commits

Im Gegensatz hierzu wird mit git reset der bestehende Commit-Verlauf verändert. Deshalb sollte git revert zum Rückgängigmachen von Änderungen an einem öffentlichen Branch genutzt werden und git reset sollte dem Rückgängigmachen von Änderungen an einem privaten Branch vorbehalten bleiben.

Du kannst dir git revert auch als Tool zum Rückgängigmachen von committeten Änderungen und git reset HEAD zum Rückgängigmachen von nicht committeten Änderungen merken.

Bei git revert, wie auch schon bei git checkout, besteht die Gefahr, dass Dateien im Arbeitsverzeichnis überschrieben werden. Daher musst du Änderungen, die während des "revert"-Vorgangs verloren gehen könnten, committen oder stashen.

File-level operations


Die Befehle git reset und git checkout akzeptieren auch einen optionalen Dateipfad als Parameter. Dies ändert ihr Verhalten erheblich. Anstatt auf ganze Snapshots werden sie nur auf einzelne Dateien angewendet.

Git reset a specific file

In Kombination mit einem Dateipfad aktualisiert git reset den Snapshot aus der Staging-Umgebung, damit dieser mit der Version des angegebenen Commits übereinstimmt. Mit diesem Befehl wird z. B. die Version von foo.py im zweitletzten Commit abgerufen und in die Staging-Umgebung überführt, damit sie in den nächsten Commit aufgenommen wird.

git reset HEAD~2 foo.py

Wie die Version von git reset auf Commit-Ebene wird dies eher mit HEAD verwendet als mit einem beliebigen Commit. Das Ausführen von git reset HEAD foo.py entfernt foo.py aus der Staging-Umgebung. Die darin enthaltenen Änderungen sind weiterhin im Arbeitsverzeichnis vorhanden.

Verschieben einer Datei vom Commit-Verlauf in den Snapshot aus der Staging-Umgebung

Die Optionen --soft, --mixed und --hard wirken sich nicht auf die Version auf Dateiebene von git reset aus, da der Snapshot in der Staging-Umgebung immer aktualisiert wird und das Arbeitsverzeichnis niemals aktualisiert wird.

Git checkout file

Das Auschecken einer Datei ähnelt der Nutzung von git reset mit einem Dateipfad, allerdings wird statt dem Staging-Bereich das Arbeitsverzeichnis aktualisiert. Anders als bei der Commit-Level-Version dieses Befehls wird die HEADReferenz nicht bewegt, sodass du nicht zwischen Branches wechseln kannst.

Verschieben einer Datei vom Commit-Verlauf in das Arbeitsverzeichnis

Der folgende Befehl sorgt beispielsweise dafür, dass foo.py im Arbeitsverzeichnis an den zweitletzten Commit angeglichen wird:

git checkout HEAD~2 foo.py

Genauso wie bei der Ausführung von git checkout auf Commit-Ebene können hiermit alte Versionen eines Projekts eingesehen werden, aber der Anwendungsbereich ist auf die spezifizierte Datei beschränkt.

Wenn du die ausgecheckte Datei in die Staging-Umgebung verschiebst und committest, führt dies dazu, dass du sie auf die alte Dateiversion zurücksetzt. Beachte, dass dabei alle nachfolgenden Änderungen an der Datei entfernt werden, während beim Befehl git revert nur die Änderungen rückgängig gemacht werden, die vom angegebenen Commit eingeführt wurden.

Wie git reset wird dies üblicherweise mit HEAD als Commit-Referenz verwendet. Beispielsweise werden mit git checkout HEAD foo.py die Änderungen an foo.py verworfen, die sich nicht in der Staging-Umgebung befinden. Dieses Verhalten ähnelt git reset HEAD --hard, bezieht sich aber nur auf die spezifizierte Datei.

Zusammenfassung


You should now have all the tools you could ever need to undo changes in a Git repository. The git reset, git checkout, and git revert commands can be confusing, but when you think about their effects on the working directory, staged snapshot, and commit history, it should be easier to discern which command fits the development task at hand.


Diesen Artikel teilen

Lesenswert

Füge diese Ressourcen deinen Lesezeichen hinzu, um mehr über DevOps-Teams und fortlaufende Updates zu DevOps bei Atlassian zu erfahren.

Mitarbeiter arbeiten mit unzähligen Tools zusammen

Bitbucket-Blog

Abbildung: DevOps

DevOps-Lernpfad

Demo Den: Feature-Demos mit Atlassian-Experten

So funktioniert Bitbucket Cloud mit Atlassian Open DevOps

Melde dich für unseren DevOps-Newsletter an

Thank you for signing up