Eine Anleitung zum Rückgängigmachen von Fehlern mit Git (Teil 2)
Veröffentlicht: 2022-03-10In diesem zweiten Teil unserer Serie „Fehler mit Git rückgängig machen“ werden wir der Gefahr wieder mutig ins Auge blicken: Ich habe vier neue Weltuntergangsszenarien vorbereitet – darunter natürlich einige clevere Möglichkeiten, unseren Hals zu retten! Aber bevor wir eintauchen: Werfen Sie einen Blick auf die vorherigen Artikel zu Git, um noch mehr Selbstrettungsmethoden zu finden, die Ihnen helfen, Ihre Fehler mit Git rückgängig zu machen!
Lass uns gehen!
Wiederherstellen eines gelöschten Zweigs mithilfe des Reflogs
Haben Sie jemals einen Zweig gelöscht und kurz darauf festgestellt, dass Sie das nicht hätten tun sollen? Für den unwahrscheinlichen Fall, dass Sie dieses Gefühl nicht kennen, kann ich Ihnen sagen, dass es kein gutes ist. Eine Mischung aus Traurigkeit und Wut beschleicht Sie, während Sie an all die harte Arbeit denken, die in die Commits dieses Zweigs geflossen ist, all den wertvollen Code, den Sie jetzt verloren haben.
Glücklicherweise gibt es eine Möglichkeit, diesen Zweig von den Toten zurückzubringen – mit Hilfe eines Git-Tools namens „Reflog“. Wir hatten dieses Tool im ersten Teil unserer Serie verwendet, aber hier ist eine kleine Auffrischung: Das Reflog ist wie ein Tagebuch, in dem Git jede Bewegung des HEAD-Zeigers in Ihrem lokalen Repository notiert. Mit anderen, weniger nerdigen Worten: Jedes Mal, wenn Sie auschecken, festschreiben, zusammenführen, rebasen, Rosinen auswählen usw., wird ein Journaleintrag erstellt. Das macht den Reflog zu einem perfekten Sicherheitsnetz, wenn etwas schief geht!
Schauen wir uns ein konkretes Beispiel an:
$ git branch * feature/login master
Wir können sehen, dass wir derzeit unsere feature/login
ausgecheckt haben. Nehmen wir an, dass dies der Zweig ist, den wir (versehentlich) löschen werden. Zuvor müssen wir jedoch zu einem anderen Branch wechseln, da wir unseren aktuellen HEAD-Branch nicht löschen können!
$ git checkout master $ git branch -d feature/login
Unser wertvoller Feature-Zweig ist jetzt weg – und ich gebe Ihnen eine Minute, um (a) die Schwere unseres Fehlers zu verstehen und (b) ein wenig zu trauern. Nachdem Sie die Tränen weggewischt haben, müssen wir einen Weg finden, diesen Zweig zurückzubringen! Lassen Sie uns das Reflog öffnen (einfach durch Eingabe von git reflog
) und sehen, was es für uns bereithält:
Hier sind einige Kommentare, die Ihnen helfen sollen, die Ausgabe zu verstehen:
- Zunächst einmal müssen Sie wissen, dass das Reflog seine Einträge chronologisch sortiert: Die neuesten Einträge stehen ganz oben in der Liste.
- Das oberste (und damit neueste) Element ist der Befehl
git checkout
, den wir vor dem Löschen des Zweigs ausgeführt haben. Es wird hier im Reflog protokolliert, weil es eine dieser „HEAD-Zeigerbewegungen“ ist, die das Reflog so pflichtbewusst aufzeichnet. - Um unseren schwerwiegenden Fehler rückgängig zu machen, können wir einfach zum Zustand davor zurückkehren – was auch sauber und übersichtlich im Reflog festgehalten wird!
Versuchen wir es also, indem wir einen neuen Zweig (mit dem Namen unseres „verlorenen“ Zweigs) erstellen, der bei diesem „vorher“-Status-SHA-1-Hash beginnt:
$ git branch feature/login 776f8ca
Und voila! Sie werden erfreut sein zu sehen, dass wir unseren scheinbar verlorenen Zweig jetzt wiederhergestellt haben!
Wenn Sie eine Git-Desktop-GUI wie „Tower“ verwenden, können Sie eine nette Abkürzung nehmen: Drücken Sie einfach CMD + Z auf Ihrer Tastatur, um den letzten Befehl rückgängig zu machen – selbst wenn Sie gerade einen Zweig gewaltsam gelöscht haben!
Verschieben eines Commits in einen anderen Branch
In vielen Teams gibt es eine Übereinkunft, develop
nicht auf langlaufende Branches wie main
oder Develop zu verpflichten: Branches wie diese sollten nur durch Integrationen (z. B. Merges oder Rebases) neue Commits erhalten . Und doch sind Fehler natürlich unvermeidlich: Manchmal vergessen und binden wir uns trotzdem an diese Zweige! Wie können wir also das Chaos beseitigen, das wir angerichtet haben?
Glücklicherweise können diese Arten von Problemen leicht behoben werden. Krempeln wir die Ärmel hoch und machen uns an die Arbeit.
Der erste Schritt besteht darin, zum richtigen Zielzweig zu wechseln und dann den Commit mit dem cherry-pick
Befehl zu verschieben:
$ git checkout feature/login $ git cherry-pick 776f8caf
Sie haben jetzt das Commit auf dem gewünschten Zweig, wo es ursprünglich hätte sein sollen. Fantastisch!
Aber eines bleibt noch zu tun: Wir müssen den Ast aufräumen, wo er zuerst versehentlich gelandet ist! Der cherry-pick
Befehl hat sozusagen eine Kopie des Commit erstellt – aber das Original ist immer noch auf unserem lang laufenden Zweig vorhanden:
Das bedeutet, dass wir zu unserem lang laufenden Zweig zurückwechseln und git reset
verwenden müssen, um ihn zu entfernen:
$ git checkout main $ git reset --hard HEAD~1
Wie Sie sehen können, verwenden wir hier den Befehl git reset
, um den fehlerhaften Commit zu löschen. Der Parameter HEAD~1
weist Git an, „eine Revision hinter HEAD zurückzugehen“, wodurch effektiv das oberste (und in unserem Fall: unerwünschte) Commit aus der Historie dieses Zweigs gelöscht wird.
Und voila: Der Commit ist jetzt dort, wo er ursprünglich hätte sein sollen, und unser langjähriger Zweig ist sauber – als wäre unser Fehler nie passiert!
Bearbeiten der Nachricht eines alten Commit
Es ist allzu leicht, einen Tippfehler in eine Commit-Nachricht zu schmuggeln – und ihn erst viel später zu entdecken. In einem solchen Fall kann die gute alte Option --amend
von git commit
nicht verwendet werden, um dieses Problem zu beheben, da sie nur für den allerletzten Commit funktioniert. Um einen älteren Commit zu korrigieren, müssen wir auf ein Git-Tool namens „Interactive Rebase“ zurückgreifen.
Zuerst müssen wir Interactive Rebase mitteilen, welchen Teil des Commit-Verlaufs wir bearbeiten möchten. Dies geschieht, indem wir ihm einen Commit-Hash zuführen: den übergeordneten Commit desjenigen, den wir manipulieren möchten.
$ git rebase -i 6bcf266b
Daraufhin öffnet sich ein Editorfenster. Es enthält eine Liste aller Commits nach dem, den wir als Grundlage für das Interactive Rebase im Befehl bereitgestellt haben:
Hier ist es wichtig, dass Sie nicht Ihrem ersten Impuls folgen: In diesem Schritt bearbeiten wir die Commit-Nachricht noch nicht . Stattdessen teilen wir Git nur mit, welche Art von Manipulation wir mit welchem Commit(s) durchführen wollen. Praktischerweise gibt es eine Liste mit Aktionsschlüsselwörtern, die in den Kommentaren unten in diesem Fenster vermerkt sind. Für unseren Fall markieren wir Zeile #1 mit reword
(wodurch das Standardpick pick
wird).
In diesem Schritt müssen Sie nur noch speichern und das Editorfenster schließen. Im Gegenzug öffnet sich ein neues Editor-Fenster, das die aktuelle Nachricht des von uns markierten Commits enthält. Und jetzt ist es endlich an der Zeit, unsere Änderungen vorzunehmen!
Hier ist der gesamte Ablauf für Sie auf einen Blick:
Korrigieren eines fehlerhaften Commit (auf sehr elegante Weise)
Abschließend werfen wir einen Blick auf fixup
, das Schweizer Taschenmesser der Undoing-Tools. Einfach ausgedrückt, ermöglicht es Ihnen, einen fehlerhaften/unvollständigen/falschen Commit nachträglich zu beheben. Es ist aus zwei Gründen wirklich ein wunderbares Werkzeug:
- Es spielt keine Rolle, was das Problem ist.
Möglicherweise haben Sie vergessen, eine Datei hinzuzufügen, sollten etwas gelöscht haben, eine falsche Änderung vorgenommen haben oder einfach einen Tippfehler gemacht haben.fixup
funktioniert in all diesen Situationen! - Es ist äußerst elegant.
Unsere normale, instinktive Reaktion auf einen Fehler in einem Commit besteht darin, einen neuen Commit zu erstellen, der das Problem behebt. Diese Arbeitsweise, so intuitiv sie auch erscheinen mag, lässt Ihren Commit-Verlauf sehr bald sehr chaotisch aussehen. Sie haben „Original“-Commits und dann diese kleinen „Pflaster“-Commits, die die Dinge beheben, die bei den Original-Commits schief gelaufen sind. Ihr Verlauf ist übersät mit kleinen, bedeutungslosen Pflaster-Commits, was es schwierig macht, zu verstehen, was in Ihrer Codebasis passiert ist.
Hier kommt das fixup
ins Spiel. Es ermöglicht Ihnen, immer noch dieses korrigierende Pflaster durchzuführen. Aber hier kommt die Magie: Es wendet es dann auf das ursprüngliche, kaputte Commit an (repariert es auf diese Weise) und verwirft dann das hässliche Band-Aid-Commit vollständig!
Wir können gemeinsam ein Praxisbeispiel durchgehen! Nehmen wir an, dass der ausgewählte Commit hier defekt ist.
Nehmen wir auch an, dass ich Änderungen in einer Datei namens error.html
vorbereitet habe, die das Problem lösen werden. Hier ist der erste Schritt, den wir machen müssen:
$ git add error.html $ git commit --fixup 2b504bee
Wir erstellen einen neuen Commit, aber wir sagen Git, dass dies ein besonderer ist: Es ist ein Fix für einen alten Commit mit dem angegebenen SHA-1-Hash (in diesem Fall 2b504bee
).
Der zweite Schritt besteht nun darin, eine Interactive Rebase-Sitzung zu starten – denn fixup
gehört zum großen Toolset von Interactive Rebase.
$ git rebase -i --autosquash 0023cddd
Zwei Dinge sind es wert, über diesen Befehl erklärt zu werden. Erstens, warum habe ich hier 0023cddd
als Revisions-Hash angegeben? Weil wir unsere interaktive Rebase-Sitzung beim übergeordneten Commit unseres kaputten Kollegen starten müssen.
Zweitens, wofür ist die Option --autosquash
? Es nimmt uns viel Arbeit ab! In dem sich nun öffnenden Editorfenster ist bereits alles für uns vorbereitet:
Dank der Option --autosquash
hat Git bereits die schwere Arbeit für uns erledigt:
- Es markierte unser kleines Pflaster-Commit mit dem
fixup
-Action-Schlüsselwort. Auf diese Weise kombiniert Git es mit dem Commit direkt darüber und verwirft es dann. - Es hat auch die Zeilen entsprechend neu geordnet und unser Band-Aid-Commit direkt unter das Commit verschoben, das wir reparieren möchten (nochmals:
fixup
funktioniert durch Kombinieren des markierten Commits mit dem darüber !).
Kurz gesagt: Uns bleibt nichts anderes übrig, als die Fenster zu schließen!
Werfen wir einen letzten Blick auf das Endergebnis.
- Der ehemals defekte Commit ist behoben: Er enthält jetzt die Änderungen, die wir in unserem Band-Aid-Commit vorbereitet haben.
- Der hässliche Pflaster-Commit selbst wurde verworfen: Der Commit-Verlauf ist sauber und einfach zu lesen – als ob überhaupt kein Fehler aufgetreten wäre.
Zu wissen, wie man Fehler rückgängig macht, ist eine Superkraft
Glückwünsche! Sie können jetzt in vielen schwierigen Situationen Ihren Hals retten! Wir können diese Situationen nicht wirklich vermeiden: Egal wie erfahren wir als Entwickler sind, Fehler gehören einfach zum Job. Aber jetzt, da Sie wissen, wie man mit ihnen umgeht, können Sie ihnen mit einem entspannten Herzschlag begegnen.
Wenn Sie mehr über das Rückgängigmachen von Fehlern mit Git erfahren möchten, kann ich Ihnen das kostenlose „First Aid Kit for Git“ empfehlen, eine Reihe von kurzen Videos zu genau diesem Thema.
Haben Sie Spaß daran, Fehler zu machen – und natürlich, sie mit Leichtigkeit rückgängig zu machen!