Close

Commits und Änderungen rückgängig machen

In diesem Abschnitt behandeln wir die verfügbaren Git-Strategien und -Befehle zum Rückgängigmachen von Änderungen. Zuallererst ist zu beachten, dass Git nicht über eine herkömmliche "Rückgängig"-Funktion verfügt wie in einem Textverarbeitungsprogramm. Git-Vorgänge sollten also lieber nicht mit herkömmlichen Systemen zum Rückgängigmachen von Änderungen in Verbindung gebracht werden. Außerdem hat Git seine eigene Nomenklatur für diese Vorgänge zum Rückgängigmachen, die im Folgenden sinnvollerweise auch verwendet werden sollte. Diese Nomenklatur umfasst Begriffe wie reset, revert, checkout, clean usw.

Spaßeshalber kann Git als Hilfsmittel zum Verwalten von Zeitleisten betrachtet werden. Commits sind Snapshots eines Zeitpunkts oder von wichtigen Punkten auf der Zeitleiste eines Projektverlaufs. Zusätzlich können mithilfe von Branches mehrere Zeitleisten verwaltet werden. Rückgängigmachen in Git heißt also normalerweise, dass die Zeit zurückgedreht wird oder zu einer Zeitleiste gewechselt wird, auf der Fehler nicht stattgefunden haben.

Dieses Tutorial vermittelt dir alle Kompetenzen, die du benötigst, um mit älteren Überarbeitungen eines Softwareprojekts zu arbeiten. Zunächst zeigen wir dir, wie du alte Commits untersuchen kannst, und erklären dann den Unterschied zwischen dem Rückgängigmachen öffentlicher Commits im Projektverlauf und dem Zurücksetzen nicht veröffentlichter Änderungen auf deiner lokalen Maschine.


Verlorenes wiederfinden: Durchsehen alter Commits


Der grundlegende Sinn und Zweck eines Versionskontrollsystems ist die Speicherung "sicherer" Kopien eines Projekts. Das heißt: Du musst dir keine Sorgen mehr machen, dass deine Codebasis irreparabel geschädigt wird. Ist erst einmal ein Projektverlauf der Commits erstellt, kannst du jeden Commit im Verlauf erneut aufrufen und prüfen. Eines der besten Dienstprogramme zum Überprüfen des Verlaufs eines Git-Repositorys ist der Befehl git log. Im unten gezeigten Beispiel rufen wir mit git log eine Liste der letzten Commits für eine gängige Open-Source-Grafikbibliothek ab.

git log --oneline
e2f9a78fe Replaced FlyControls with OrbitControls
d35ce0178 Editor: Shortcuts panel Safari support.
9dbe8d0cf Editor: Sidebar.Controls to Sidebar.Settings.Shortcuts. Clean up.
05c5288fc Merge pull request #12612 from TyLindberg/editor-controls-panel
0d8b6e74b Merge pull request #12805 from harto/patch-1
23b20c22e Merge pull request #12801 from gam0022/improve-raymarching-example-v2
fe78029f1 Fix typo in documentation
7ce43c448 Merge pull request #12794 from WestLangley/dev-x
17452bb93 Merge pull request #12778 from OndrejSpanel/unitTestFixes
b5c1b5c70 Merge pull request #12799 from dhritzkiv/patch-21
1b48ff4d2 Updated builds.
88adbcdf6 WebVRManager: Clean up.
2720fbb08 Merge pull request #12803 from dmarcos/parentPoseObject
9ed629301 Check parent of poseObject instead of camera
219f3eb13 Update GLTFLoader.js
15f13bb3c Update GLTFLoader.js
6d9c22a3b Update uniforms only when onWindowResize
881b25b58 Update ProjectionMatrix on change aspect
Git-Logo
Zugehöriges Material

Git-Merkzettel

Bitbucket-Logo
Lösung anzeigen

Git kennenlernen mit Bitbucket Cloud

Jeder Commit verfügt über einen eindeutigen SHA-1-Hash zur Identifikation. Anhand dieser IDs bewegt man sich durch die Zeitleiste durchgeführter Commits und sieht sie erneut an. Standardmäßig zeigt git log nur Commits für den aktuell ausgewählten Branch an. Es ist aber durchaus möglich, dass sich der von dir gesuchte Commit in einem anderen Branch befindet. Du kannst sämtliche Commits aller Branches ansehen, indem du git log --branches=* ausführst. Der Befehl git branch wird zur Anzeige und zum Aufrufen anderer Branches verwendet. Der Befehl git branch -a gibt eine Liste aller bekannten Branch-Namen zurück. Einer dieser Branch-Namen kann nun mit git log protokolliert werden.

Wenn du eine Commit-Referenz zu dem Zeitpunkt gefunden hast, zu dem du zurückkehren möchtest, kannst du mit dem Befehl git checkout diesen Commit aufrufen. Git checkout ist eine einfache Methode, diese gespeicherten Snapshots auf deinen Entwicklungsrechner zu "laden". Während des normalen Entwicklungsprozesses verweist HEAD üblicherweise auf den main-Branch oder einen anderen lokalen Branch, aber wenn du einen alten Commit auscheckst, verweist HEAD nicht mehr auf einen Branch – er verweist direkt auf einen Commit. Dies wird als "detached HEAD" bezeichnet und kann folgendermaßen dargestellt werden:

Älteren Commit auschecken

Beim Aufrufen einer alten Datei wird der HEAD-Verweis nicht verschoben. Er verbleibt beim selben Branch und beim selben Commit, um einen losgelösten HEAD zu vermeiden. Du kannst die alte Version der Datei dann in Form eines neuen Snapshots erneut committen, ganz wie jede andere Änderung auch. Wenn du git checkout auf diese Weise für eine Datei einsetzt, führst du also im Grunde genommen eine Zurücksetzung auf eine ältere Version der betreffenden Datei durch. Weitere Informationen zu diesen zwei Modi findest du auf der Seite git checkout.

Alte Überarbeitung anzeigen lassen


In diesem Beispiel gehen wir davon aus, dass du mit der Entwicklung eines verrückten Experiments begonnen hast, aber nicht weißt, ob du es aufbewahren willst. Um dir die Entscheidung zu erleichtern, willst du dir vor dem Experiment den Projektstatus ansehen. Zunächst musst du die ID der gesuchten Überarbeitung finden.

git log --oneline

Nehmen wir mal an, dein Projektverlauf sieht etwa so aus:

b7119f2 Continue doing crazy things
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Du kannst git checkout verwenden, um den Commit "Make some import changes to hello.txt" wie folgt anzuzeigen:

git checkout a1e8fb5

Dein Arbeitsverzeichnis befindet sich dann in exakt demselben Zustand wie der Commit a1e8fb5. Du kannst dir Dateien ansehen, das Projekt kompilieren, Tests durchführen und sogar Dateien bearbeiten, ohne befürchten zu müssen, dass der aktuelle Projektstatus verloren geht. Keine deiner Aktionen und Änderungen wird im Repository gespeichert. Wenn du weiter an deinem Projekt arbeiten möchtest, musst du wieder in den "aktuellen" Projektstatus wechseln:

git checkout main

Dabei wird vorausgesetzt, dass du auf dem standardmäßigen main-Branch entwickelst. Sobald du wieder im main-Branch bist, kannst du entweder git revert oder git reset nutzen, um unerwünschte Änderungen rückgängig zu machen.

Rückgängigmachen eines committeten Snapshots


Es gibt verschiedene Techniken, um einen Commit "rückgängig zu machen". Für die nächsten Beispiele gehen wir von folgendem Commit-Verlauf aus:

git log --oneline
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Wir werden uns nun darauf konzentrieren, den Commit 872fa7e Try something crazy rückgängig zu machen. Vielleicht ist das ja alles ein bisschen zu verrückt geworden.

So wird ein Commit mit "git checkout" rückgängig gemacht


Mit dem Befehl git checkout können wir den vorherigen Commit, a1e8fb5, auschecken und das Repository in den Status zurückversetzen, den es vor dem "verrückten" Commit hatte. Durch das Auschecken eines bestimmten Commits wird das Repository in einen Status mit losgelöstem HEAD versetzt. Das heißt, du arbeitest auf keinem Branch mehr. Im losgelösten Status verwaisen alle neu vorgenommenen Commits, sobald du zu einem eingerichteten Branch zurückkehrst. Verwaiste Commits werden bei der nächsten Speicherbereinigung von Git gelöscht. Die Speicherbereinigung erfolgt in konfigurierten Zeitabständen und entfernt verwaiste Commits endgültig. Damit verwaiste Commits nicht der Speicherbereinigung zum Opfer fallen, müssen wir sicherstellen, dass wir uns in einem Branch befinden.

Im Status mit losgelöstem HEAD können wir git checkout -b new_branch_without_crazy_commit ausführen. Hierdurch wird ein neuer Branch namens new_branch_without_crazy_commit erstellt und in diesen Status gewechselt. Das Repository befindet sich nun in einer neuen Verlaufszeitleiste, in der der Commit 872fa7e nicht mehr existiert. Nun können wir in diesem neuen Branch, in dem der Commit 872fa7e nicht mehr existiert, arbeiten und den Commit als rückgängig gemacht betrachten. Leider ist diese Strategie nicht geeignet, wenn du den vorherigen Branch benötigst, weil es vielleicht dein main-Branch war. Sehen wir uns deshalb ein paar andere Strategien zum Rückgängigmachen von Änderungen an. Weitere Informationen und Beispiele findest du in unserer detaillierten Behandlung von git checkout.

So wird ein Commit mit "git revert" rückgängig gemacht


Wir gehen nun wieder von unserem ursprünglichen Beispiel des Commit-Verlaufs aus. Es geht um den Verlauf mit dem Commit 872fa7e. Dieses Mal versuchen wir, den Commit durch Zurücksetzen "rückgängig zu machen". Wenn wir git revert HEAD ausführen, wird von Git ein neuer Commit mit der gegenteiligen Aktion zum letzten Commit erstellt. Dem aktuellen Branch-Verlauf wird ein neuer Commit hinzugefügt, sodass er wie folgt aussieht:

git log --oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

An dieser Stelle haben wir den Commit 872fa7e rein technisch rückgängig gemacht. Obwohl 872fa7e immer noch im Verlauf aufgeführt ist, ist der neue Commit e2f9a78 eine Umkehrung der Änderungen in 872fa7e. Im Gegensatz zu unserer vorherigen Checkout-Strategie können wir weiterhin denselben Branch verwenden. Diese Lösung ist ein zufriedenstellender Rückgängig-Vorgang. Für die Arbeit mit öffentlich freigegebenen Repositorys ist dies sogar die ideale Methode. Falls du einen geordneten und minimalen Git-Verlauf brauchen solltest, ist diese Strategie aber eventuell ungeeignet.

So wird ein Commit mit "git reset" rückgängig gemacht


Für diese Technik zum Rückgängigmachen bleiben wir bei unserem Arbeitsbeispiel. git reset ist ein vielseitiger Befehl mit verschiedenen Einsatzmöglichkeiten und Funktionen. Wenn wir git reset --hard a1e8fb5 aufrufen, wird der Commit-Verlauf auf diesen speziellen Commit zurückgesetzt. Beim Abrufen des Commit-Verlaufs mit git log erhalten wir nun folgendes Ergebnis:

git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import

Die Protokollausgabe zeigt, dass die Commits e2f9a78 und 872fa7e nicht mehr im Commit-Verlauf vorhanden sind. Nun können wir weiterarbeiten und neue Commits erstellen, als ob es die "verrückten" Commits nie gegeben hätte. Diese Methode zum Rückgängigmachen von Änderungen hält den Verlauf am saubersten. Das Zurücksetzen eignet sich bestens für lokale Änderungen, kann aber in einem gemeinsamen Remote-Repository zu Komplikationen führen. Wenn wir ein gemeinsames Remote-Repository verwenden, zu dem der Commit 872fa7e gepusht wird, und wir für einen Branch git push verwenden, auf dem wir den Verlauf zurückgesetzt haben, bemerkt Git dies und gibt eine Fehlermeldung aus. Git wird annehmen, dass der gepushte Branch nicht aktuell ist, da Commits fehlen. In solchen Szenarien sollte git revert als Methode zum Rückgängigmachen bevorzugt werden.

Rückgängigmachen des letzten Commits


Im vorigen Abschnitt haben wir die verschiedenen Strategien zum Rückgängigmachen von Commits besprochen. Diese Strategien können alle auch auf den neuesten Commit angewendet werden. In einigen Fällen musst du jedoch den letzten Commit nicht unbedingt entfernen oder zurücksetzen. Vielleicht wurde dies etwas vorschnell gemacht. In diesem Fall kannst du den neuesten Commit ergänzen. Nachdem du weitere Änderungen im Arbeitsverzeichnis vorgenommen hast und diese für den Commit mit git add bereitgestellt hast, kannst du git commit --amend ausführen. Damit öffnet Git den konfigurierten System-Editor, in dem du die letzte Commit-Nachricht ändern kannst. Die neuen Änderungen werden dem ergänzten Commit hinzugefügt.

Rückgängigmachen nicht committeter Änderungen


Bevor Änderungen in den Repository-Verlauf committet werden, befinden sie sich im Staging-Index und im Arbeitsverzeichnis. Du musst die Änderungen in diesen beiden Bereichen eventuell rückgängig machen. Der Staging-Index und das Arbeitsverzeichnis sind interne Git-Mechanismen für das Statusmanagement. Detaillierte Informationen zur Funktionsweise dieser Mechanismen findest du auf der git reset-Seite.

Das Arbeitsverzeichnis


Das Arbeitsverzeichnis ist in der Regel mit dem lokalen Dateisystem synchronisiert. Zum Rückgängigmachen von Änderungen im Arbeitsverzeichnis kannst du Dateien ganz normal in deinem bevorzugten Editor bearbeiten. Git verfügt über ein paar Hilfsmittel, die beim Management des Arbeitsverzeichnisses behilflich sind. Da wäre der Befehl git clean, mit dem Änderungen am Arbeitsverzeichnis bequem rückgängig gemacht werden können. Außerdem kann noch git reset mit den Optionen --mixed oder --hard aufgerufen werden, um das Arbeitsverzeichnis zurückzusetzen.

Der Staging-Index


Der Befehl git add wird zum Hinzufügen von Änderungen zum Staging-Index verwendet. Git reset wird vor allem zum Rückgängigmachen von Änderungen am Staging-Index verwendet. Eine Rücksetzung mit --mixed verschiebt alle ausstehenden Änderungen vom Staging-Index zurück ins Arbeitsverzeichnis.

Rückgängigmachen öffentlicher Änderungen


Bei der Arbeit in einem Team mit Remote-Repositorys müssen beim Rückgängigmachen von Änderungen zusätzliche Aspekte bedacht werden. Git reset sollte im Allgemeinen als eine lokale Methode zum Rückgängigmachen betrachtet werden. Ein Reset sollte durchgeführt werden, wenn Änderungen an einem privaten Branch rückgängig gemacht werden. So wird die Entfernung von Commits auf sichere Weise von anderen Branches getrennt, die möglicherweise von anderen Entwicklern genutzt werden. Probleme entstehen, wenn ein Reset in einem gemeinsamen Branch durchgeführt und dieser dann remote mit git push gepusht wird. Git wird den Push blockieren, da es den Branch als veraltet betrachtet, weil ihm gegenüber dem Remote-Branch Commits fehlen.

Die bevorzugte Methode zum Zurücksetzen eines geteilten Verlaufs ist git revert. Eine Zurücksetzung mit "revert" ist sicherer als mit "reset", weil dabei keine Commits aus einem geteilten Verlauf entfernt werden. Beim Revert bleiben die Commits, die rückgängig gemacht werden sollen, erhalten. Es wird ein neuer Commit erstellt, der die Wirkung des unerwünschten Commits aufhebt. Diese Methode ist bei der Remote-Zusammenarbeit sicherer, weil ein Remote-Entwickler dann einen Pull für den Branch durchführen kann, um den neuen Commit zu erhalten, der den unerwünschten Commit rückgängig macht.

Zusammenfassung


Wir haben nun einige allgemeine Strategien für das Rückgängigmachen von Änderungen in Git behandelt. Dabei ist zu bedenken, dass es hierfür mehrere Methoden gibt. Auf dieser Seite wurden u. a. Themen angeschnitten, die auf den Seiten zu den jeweiligen Git-Befehlen im Detail erklärt werden. Die am häufigsten verwendeten Tools zum Rückgängigmachen sind git checkout, git revert und git reset. Folgende wichtige Punkte solltest du dir merken:

  • In der Regel sind einmal committete Änderungen dauerhaft.
  • Mit git checkout kannst du den Commit-Verlauf anzeigen und darin navigieren.
  • git revert ist die beste Methode, um freigegebene öffentliche Änderungen rückgängig zu machen.
  • git reset ist am besten zum Rückgängigmachen von lokalen privaten Änderungen geeignet.

Zusätzlich zu den Hauptbefehlen zum Rückgängigmachen haben wir uns andere Git-Dienstprogramme angesehen: git log zum Suchen nach verloren gegangenen Commits, git clean zum Rückgängigmachen nicht committeter Änderungen und git add zum Bearbeiten des Staging-Index.

Jeder dieser Befehle verfügt über eine eigene ausführliche Dokumentation. Wenn du mehr über einen bestimmten hier erwähnten Befehl erfahren möchtest, rufe die entsprechenden Links auf.


Diesen Artikel teilen
Nächstes Thema

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