paint-brush
Git-Geschichte mit Zuversicht neu schreiben: Ein Leitfadenvon@omerosenbaum
2,007 Lesungen
2,007 Lesungen

Git-Geschichte mit Zuversicht neu schreiben: Ein Leitfaden

von Omer Rosenbaum18m2023/04/27
Read on Terminal Reader
Read this story w/o Javascript

Zu lang; Lesen

Git ist ein System zur zeitlichen Aufzeichnung von Snapshots eines Dateisystems. Ein Git-Repository hat drei „Zustände“ oder „Bäume“: den Index, den Staging-Bereich und den Arbeitsbaum. Ein Arbeitsverzeichnis (Ortsverzeichnis) ist ein beliebiges Verzeichnis in unserem Dateisystem, dem ein Git-Repository zugeordnet ist.
featured image - Git-Geschichte mit Zuversicht neu schreiben: Ein Leitfaden
Omer Rosenbaum HackerNoon profile picture

Als Entwickler arbeiten Sie ständig mit Git.


Sind Sie jemals an einen Punkt gekommen, an dem Sie gesagt haben: „Oh-oh, was habe ich gerade gemacht?“

Wenn mit Git etwas schief geht, fühlen sich viele Ingenieure hilflos (Quelle: XKCD)


Dieser Beitrag gibt Ihnen die Werkzeuge an die Hand, mit denen Sie die Geschichte selbstbewusst neu schreiben können.

Notizen, bevor wir beginnen

  1. Ich habe auch einen Live-Vortrag über den Inhalt dieses Beitrags gehalten. Wenn Sie ein Video bevorzugen (oder es neben der Lektüre ansehen möchten), können Sie es finden Hier .


  2. Ich arbeite an einem Buch über Git! Sind Sie daran interessiert, die ersten Versionen zu lesen und Feedback zu geben? Schicken Sie mir eine E-Mail: [email protected]

Aufzeichnen von Änderungen in Git

Bevor Sie verstehen, wie man Dinge in Git rückgängig macht , sollten Sie zunächst verstehen, wie wir Änderungen in Git aufzeichnen . Wenn Sie bereits alle Begriffe kennen, können Sie diesen Teil gerne überspringen.


Es ist sehr nützlich, sich Git als ein System zum zeitlichen Aufzeichnen von Snapshots eines Dateisystems vorzustellen. Betrachtet man ein Git-Repository, so hat es drei „Zustände“ oder „Bäume“:

Die drei „Bäume“ eines Git-Repos (Quelle: https://youtu.be/ozA1V00GIT8)


Wenn wir an unserem Quellcode arbeiten, arbeiten wir normalerweise von einem Arbeitsverzeichnis aus. Ein Arbeitsverzeichnis (oder Arbeitsbaum ) ist ein beliebiges Verzeichnis in unserem Dateisystem, dem ein Repository zugeordnet ist.


Es enthält die Ordner und Dateien unseres Projekts sowie ein Verzeichnis namens .git . Den Inhalt des .git Ordners habe ich in ausführlicher beschrieben ein früherer Beitrag .


Nachdem Sie einige Änderungen vorgenommen haben, möchten Sie diese möglicherweise in Ihrem Repository aufzeichnen. Ein Repository (kurz: Repo ) ist eine Sammlung von Commits , von denen jeder ein Archiv davon ist, wie der Arbeitsbaum des Projekts zu einem früheren Zeitpunkt aussah, sei es auf Ihrem Computer oder dem eines anderen.


Ein Repository umfasst auch andere Dinge als unsere Codedateien, wie z. B. HEAD , Branches usw.


Dazwischen gibt es den Index oder den Staging-Bereich ; Diese beiden Begriffe sind austauschbar. Wenn wir einen Zweig checkout , füllt Git den Index mit allen Dateiinhalten, die zuletzt in unser Arbeitsverzeichnis ausgecheckt wurden, und wie sie beim ursprünglichen Auschecken aussahen.


Wenn wir git commit verwenden, wird das Commit basierend auf dem Status des Index erstellt.


Der Index bzw. der Staging-Bereich ist also Ihr Spielplatz für den nächsten Commit. Sie können mit dem Index arbeiten und machen, was Sie wollen, ihm Dateien hinzufügen, Dinge daraus entfernen und erst dann, wenn Sie bereit sind, mit der Übertragung an das Repository fortfahren.


Zeit zum Anfassen 🙌🏻


Verwenden Sie git init , um ein neues Repository zu initialisieren. Schreiben Sie einen Text in eine Datei namens 1.txt :

Ein neues Repo initiieren und die erste Datei darin erstellen (Quelle: https://youtu.be/ozA1V00GIT8)


Wo befindet sich 1.txt in den drei oben beschriebenen Baumzuständen jetzt?


Im Arbeitsbaum, da es noch nicht in den Index aufgenommen wurde.

Die Datei „1.txt“ ist jetzt nur noch Teil des Arbeitsverzeichnisses (Quelle: https://youtu.be/ozA1V00GIT8)


Um es bereitzustellen und zum Index hinzuzufügen, verwenden Sie git add 1.txt .

Mit „git add“ wird die Datei bereitgestellt, sodass sie jetzt auch im Index enthalten ist (Quelle: https://youtu.be/ozA1V00GIT8).


Jetzt können wir git commit verwenden, um unsere Änderungen im Repository zu übernehmen.

Durch die Verwendung von „git commit“ wird ein Commit-Objekt im Repository erstellt (Quelle: https://youtu.be/ozA1V00GIT8).


Sie haben ein neues Commit-Objekt erstellt, das einen Zeiger auf einen Baum enthält, der den gesamten Arbeitsbaum beschreibt. In diesem Fall wird es nur 1.txt im Stammordner sein. Zusätzlich zu einem Zeiger auf den Baum enthält das Commit-Objekt Metadaten wie Zeitstempel und Autoreninformationen.


Weitere Informationen zu den Objekten in Git (z. B. Commits und Bäume) finden Sie unter Schauen Sie sich meinen vorherigen Beitrag an .


(Ja, „check out“, Wortspiel beabsichtigt 😇)


Git teilt uns auch den SHA-1-Wert dieses Commit-Objekts mit. In meinem Fall war es c49f4ba (das sind nur die ersten 7 Zeichen des SHA-1-Werts, um etwas Platz zu sparen).


Wenn Sie diesen Befehl auf Ihrem Computer ausführen, erhalten Sie einen anderen SHA-1-Wert, da Sie ein anderer Autor sind. Außerdem würden Sie den Commit mit einem anderen Zeitstempel erstellen.


Wenn wir das Repo initialisieren, erstellt Git einen neuen Zweig (standardmäßig main genannt). Und Ein Branch in Git ist lediglich ein benannter Verweis auf einen Commit . Standardmäßig haben Sie also nur den main . Was passiert, wenn Sie mehrere Filialen haben? Woher weiß Git, welcher Zweig der aktive Zweig ist?


Git hat einen weiteren Zeiger namens HEAD , der (normalerweise) auf einen Zweig zeigt, der dann auf einen Commit zeigt. Übrigens, unter der Haube, HEAD ist nur eine Datei. Es enthält den Namen des Zweigs mit einigen Präfixen.


Zeit, weitere Änderungen am Repo vorzunehmen!


Jetzt möchte ich ein weiteres erstellen. Erstellen wir also eine neue Datei und fügen sie wie zuvor zum Index hinzu:

Die Datei „2.txt“ befindet sich im Arbeitsverzeichnis und im Index, nachdem sie mit „git add“ bereitgestellt wurde (Quelle: https://youtu.be/ozA1V00GIT8).


Jetzt ist es an der Zeit, git commit zu verwenden. Wichtig ist, dass git commit zwei Dinge bewirkt:


Zunächst wird ein Commit-Objekt erstellt, sodass es in der internen Objektdatenbank von Git ein Objekt mit einem entsprechenden SHA-1-Wert gibt. Dieses neue Commit-Objekt verweist auch auf das übergeordnete Commit. Das ist der Commit, auf den HEAD hingewiesen hat, als Sie den Befehl git commit geschrieben haben.

Zunächst wurde ein neues Commit-Objekt erstellt – „main“ verweist immer noch auf den vorherigen Commit (Quelle: https://youtu.be/ozA1V00GIT8)


Zweitens verschiebt git commit den Zeiger des aktiven Zweigs – in unserem Fall wäre das main , um auf das neu erstellte Commit-Objekt zu zeigen.

„git commit“ aktualisiert außerdem den aktiven Zweig, sodass er auf das neu erstellte Commit-Objekt verweist (Quelle: https://youtu.be/ozA1V00GIT8)


Rückgängigmachen der Änderungen

Um die Geschichte neu zu schreiben, beginnen wir damit, den Prozess der Einführung eines Commits rückgängig zu machen. Dazu lernen wir den Befehl git reset kennen, ein superleistungsfähiges Tool.

git reset --soft

Der allerletzte Schritt, den Sie zuvor gemacht haben, war also git commit , was eigentlich zwei Dinge bedeutet: Git hat ein Commit-Objekt erstellt und main , den aktiven Zweig, verschoben. Um diesen Schritt rückgängig zu machen, verwenden Sie den Befehl git reset --soft HEAD~1 .


Die Syntax HEAD~1 bezieht sich auf das erste übergeordnete Element von HEAD . Wenn ich mehr als ein Commit im Commit-Diagramm hätte, sagen Sie „Commit 3“, was auf „Commit 2“ verweist, was wiederum auf „Commit 1“ verweist.


Und sagen wir, HEAD zeigte auf „Commit 3“. Sie könnten HEAD~1 verwenden, um auf „Commit 2“ zu verweisen, und HEAD~2 würde sich auf „Commit 1“ beziehen.


Also zurück zum Befehl: git reset --soft HEAD~1


Dieser Befehl fordert Git auf, zu ändern, worauf HEAD verweist. (Hinweis: In den Diagrammen unten verwende ich *HEAD für „was auch immer HEAD zeigt“). In unserem Beispiel zeigt HEAD auf main . Git ändert also nur den Zeiger von main so, dass er auf HEAD~1 zeigt. Das heißt, main zeigt auf „Commit 1“.


Dieser Befehl hatte jedoch keine Auswirkungen auf den Status des Index oder des Arbeitsbaums. Wenn Sie also git status verwenden, werden Sie sehen, dass 2.txt bereitgestellt wird, genau wie vor der Ausführung von git commit .

Zurücksetzen von „main“ auf „Commit 1“ (Quelle: https://youtu.be/ozA1V00GIT8)


Was ist mit git log? Es beginnt bei HEAD , geht zu main und dann zu „Commit 1“. Beachten Sie, dass dies bedeutet, dass „Commit 2“ aus unserem Verlauf nicht mehr erreichbar ist.


Bedeutet das, dass das Commit-Objekt von „Commit 2“ gelöscht wird? 🤔


Nein, es ist nicht gelöscht. Es befindet sich weiterhin in der internen Objektdatenbank von Git.


Wenn Sie den aktuellen Verlauf jetzt mithilfe von git push pushen, pusht Git „Commit 2“ nicht auf den Remote-Server, aber das Commit-Objekt ist weiterhin in Ihrer lokalen Kopie des Repositorys vorhanden.


Führen Sie nun erneut einen Commit durch – und verwenden Sie die Commit-Nachricht von „Commit 2.1“, um dieses neue Objekt vom ursprünglichen „Commit 2“ zu unterscheiden:

Erstellen eines neuen Commits (Quelle: https://youtu.be/ozA1V00GIT8)


Warum sind „Commit 2“ und „Commit 2.1“ unterschiedlich? Auch wenn wir dieselbe Commit-Nachricht verwendet haben und obwohl sie darauf verweisen das gleiche Baumobjekt (des Stammordners bestehend aus 1.txt und 2.txt ) haben sie dennoch unterschiedliche Zeitstempel, da sie zu unterschiedlichen Zeiten erstellt wurden.


In der Zeichnung oben habe ich „Commit 2“ beibehalten, um Sie daran zu erinnern, dass es immer noch in der internen Objektdatenbank von Git vorhanden ist. Sowohl „Commit 2“ als auch „Commit 2.1“ zeigen jetzt auf „Commit 1“, aber nur „Commit 2.1“ ist von HEAD aus erreichbar.

Git Reset – Gemischt

Es ist an der Zeit, sogar noch einen Schritt zurückzugehen und noch mehr rückgängig zu machen. Verwenden Sie dieses Mal git reset --mixed HEAD~1 (Hinweis: --mixed ist der Standardschalter für git reset ).


Dieser Befehl startet genauso wie git reset --soft HEAD~1 . Das heißt, es nimmt den Zeiger dessen, worauf HEAD gerade zeigt, also den main , und setzt ihn auf HEAD~1 , in unserem Beispiel – „Commit 1“.

Der erste Schritt von „git reset --mixed“ ist der gleiche wie „git reset --soft“ (Quelle: https://youtu.be/ozA1V00GIT8)


Als nächstes geht Git noch einen Schritt weiter und macht die Änderungen, die wir am Index vorgenommen haben, effektiv rückgängig. Das heißt, den Index so ändern, dass er mit dem aktuellen HEAD übereinstimmt, dem neuen HEAD , nachdem er im ersten Schritt festgelegt wurde.


Wenn wir git reset --mixed HEAD~1 ausführen würden, bedeutet dies, dass HEAD auf HEAD~1 („Commit 1“) gesetzt würde und Git dann den Index dem Status „Commit 1“ zuordnen würde – in diesem Fall es bedeutet, dass 2.txt nicht mehr Teil des Index ist.

Der zweite Schritt von „git reset --mixed“ besteht darin, den Index mit dem neuen „HEAD“ abzugleichen (Quelle: https://youtu.be/ozA1V00GIT8)


Es ist Zeit, ein neues Commit mit dem Status des ursprünglichen „Commit 2“ zu erstellen. Dieses Mal müssen wir 2.txt erneut bereitstellen, bevor wir es erstellen:

Erstellen von „Commit 2.2“ (Quelle: https://youtu.be/ozA1V00GIT8)


Git-Reset – Schwer

Mach weiter, mach noch mehr rückgängig!


Fahren Sie fort und führen Sie git reset --hard HEAD~1 aus


Auch hier beginnt Git mit der --soft Phase und setzt HEAD , auf den er zeigt ( main ), auf HEAD~1 („Commit 1“).

Der erste Schritt von „git reset --hard“ ist der gleiche wie „git reset --soft“ (Quelle: https://youtu.be/ozA1V00GIT8)


So weit, ist es gut.


Fahren Sie als Nächstes mit der Phase --mixed fort und gleichen Sie den Index mit HEAD ab. Das heißt, Git macht das Staging von 2.txt rückgängig.

Der zweite Schritt von „git reset --hard“ ist der gleiche wie „git reset --mixed“ (Quelle: https://youtu.be/ozA1V00GIT8)


Es ist Zeit für den Schritt --hard , bei dem Git noch weiter geht und das Arbeitsverzeichnis mit der Stufe des Index abgleicht. In diesem Fall bedeutet das, dass auch 2.txt aus dem Arbeitsverzeichnis entfernt wird.

Der dritte Schritt von „git reset --hard“ gleicht den Status des Arbeitsverzeichnisses mit dem des Index ab (Quelle: https://youtu.be/ozA1V00GIT8)


(**Hinweis: In diesem speziellen Fall wird die Datei nicht verfolgt, sodass sie nicht aus dem Dateisystem gelöscht wird. Dies ist jedoch nicht wirklich wichtig, um git reset zu verstehen.)


Um also eine Änderung an Git vorzunehmen, sind drei Schritte erforderlich. Sie ändern das Arbeitsverzeichnis, den Index oder den Staging-Bereich und übertragen dann einen neuen Snapshot mit diesen Änderungen. Um diese Änderungen rückgängig zu machen:


  • Wenn wir git reset --soft verwenden, machen wir den Commit-Schritt rückgängig.


  • Wenn wir git reset --mixed verwenden, machen wir auch den Staging-Schritt rückgängig.


  • Wenn wir git reset --hard verwenden, machen wir die Änderungen am Arbeitsverzeichnis rückgängig.

Szenarien aus dem wirklichen Leben!

Szenario 1

Schreiben Sie also in einem realen Szenario „Ich liebe Git“ in eine Datei ( love.txt ), da wir alle Git lieben 😍. Machen Sie weiter, inszenieren Sie und begehen Sie auch Folgendes:

Erstellen von „Commit 2.3“ (Quelle: https://youtu.be/ozA1V00GIT8)


Oh, ups!


Eigentlich wollte ich nicht, dass du es begehst.


Eigentlich wollte ich, dass Sie noch ein paar liebevolle Worte in diese Datei schreiben, bevor Sie sie festschreiben.

Was kannst du tun?


Nun, eine Möglichkeit, dies zu umgehen, wäre die Verwendung von git reset --mixed HEAD~1 , wodurch sowohl die Commit- als auch die Staging-Aktionen, die Sie durchgeführt haben, effektiv rückgängig gemacht werden:

Rückgängigmachen der Staging- und Commit-Schritte (Quelle: https://youtu.be/ozA1V00GIT8)


main zeigt also erneut auf „Commit 1“ und love.txt ist nicht mehr Teil des Index. Die Datei bleibt jedoch im Arbeitsverzeichnis. Sie können jetzt fortfahren und weitere Inhalte hinzufügen:

Weitere Liebestexte hinzufügen (Quelle: https://youtu.be/ozA1V00GIT8)


Machen Sie weiter, stellen Sie Ihre Datei bereit und übergeben Sie sie:

Erstellen des neuen Commits mit dem gewünschten Status (Quelle: https://youtu.be/ozA1V00GIT8)


Gut gemacht 👏🏻


Sie haben diesen klaren, schönen Verlauf von „Commit 2.4“, der auf „Commit 1“ verweist.


Wir haben jetzt ein neues Tool in unserer Toolbox, git reset 💪🏻

Git Reset ist jetzt in unserer Toolbox (Quelle: https://youtu.be/ozA1V00GIT8)


Dieses Tool ist super, super nützlich und man kann damit fast alles erreichen. Es ist nicht immer das bequemste Tool, kann aber bei sorgfältiger Verwendung nahezu jedes Szenario zum Umschreiben des Verlaufs lösen.


Für Anfänger empfehle ich, fast immer, wenn Sie in Git rückgängig machen möchten, nur git reset zu verwenden. Sobald Sie damit vertraut sind, ist es an der Zeit, zu anderen Tools überzugehen.

Szenario Nr. 2

Betrachten wir einen anderen Fall.


Erstellen Sie eine neue Datei mit dem Namen new.txt . Bühne und Commit:

Erstellen von „new.txt“ und „Commit 3“ (Quelle: https://youtu.be/ozA1V00GIT8)


Hoppla. Eigentlich ist das ein Fehler. Sie waren auf main und ich wollte, dass Sie diesen Commit in einem Feature-Zweig erstellen. Mein schlechtes 😇


Ich möchte, dass Sie aus diesem Beitrag zwei wichtige Werkzeuge mitnehmen. Der zweite ist git reset . Die erste und weitaus wichtigere Möglichkeit besteht darin, den aktuellen Zustand im Vergleich zu dem Zustand, in dem Sie sich befinden möchten, auf dem Whiteboard darzustellen .


Für dieses Szenario sehen der aktuelle Zustand und der gewünschte Zustand folgendermaßen aus:

Szenario Nr. 2: aktuelle vs. gewünschte Zustände (Quelle: https://youtu.be/ozA1V00GIT8)


Sie werden drei Änderungen bemerken:


  1. main deutet im aktuellen Zustand auf „Commit 3“ (das blaue) hin, im gewünschten Zustand jedoch auf „Commit 2.4“.


  2. feature Zweig existiert im aktuellen Zustand nicht, ist aber im gewünschten Zustand vorhanden und zeigt auf „Commit 3“.


  3. HEAD zeigt im aktuellen Zustand auf main und im gewünschten Zustand auf feature .


Wenn Sie dies zeichnen können und wissen, wie man git reset verwendet, können Sie sich definitiv aus dieser Situation befreien.


Also noch einmal: Das Wichtigste ist, Luft zu holen und das Ganze herauszuholen.


Wie gelangen wir anhand der Zeichnung oben vom aktuellen zum gewünschten Zustand?


Natürlich gibt es verschiedene Möglichkeiten, aber ich werde für jedes Szenario nur eine Option vorstellen. Probieren Sie auch gerne andere Optionen aus.


Sie können beginnen, indem Sie git reset --soft HEAD~1 verwenden. Dies würde main so einstellen, dass es auf den vorherigen Commit „Commit 2.4“ verweist:

„main“ ändern; „Commit 3 ist verschwommen, weil es immer noch da ist, nur nicht erreichbar (Quelle: https://youtu.be/ozA1V00GIT8)


Wenn Sie sich das aktuelle vs. gewünschte Diagramm noch einmal ansehen, können Sie erkennen, dass Sie einen neuen Zweig benötigen, oder? Sie können dafür git switch -c feature oder git checkout -b feature (die das Gleiche bewirkt) verwenden:

„Feature“-Zweig erstellen (Quelle: https://youtu.be/ozA1V00GIT8)


Dieser Befehl aktualisiert auch HEAD so, dass es auf den neuen Zweig zeigt.


Da Sie git reset --soft verwendet haben, haben Sie den Index nicht geändert, sodass er derzeit genau den Status hat, den Sie festschreiben möchten – wie praktisch! Sie können sich einfach auf den feature Zweig festlegen:

Verpflichtung zum „Feature“-Zweig (Quelle: https://youtu.be/ozA1V00GIT8)


Und Sie haben den gewünschten Zustand erreicht 🎉

Szenario Nr. 3

Sind Sie bereit, Ihr Wissen auf weitere Fälle anzuwenden?


Fügen Sie einige Änderungen an love.txt hinzu und erstellen Sie außerdem eine neue Datei mit dem Namen cool.txt . Inszenieren Sie sie und verpflichten Sie sich:

„Commit 4“ erstellen (Quelle: https://youtu.be/ozA1V00GIT8)


Oh, ups, eigentlich wollte ich, dass du zwei separate Commits erstellst, einen bei jeder Änderung 🤦🏻

Möchten Sie es selbst ausprobieren?


Sie können die Commit- und Staging-Schritte rückgängig machen:

Machen Sie Commit und Staging mit „git reset --mixed HEAD~1“ rückgängig (Quelle: https://youtu.be/ozA1V00GIT8)


Nach diesem Befehl enthält der Index diese beiden Änderungen nicht mehr, sie befinden sich jedoch beide weiterhin in Ihrem Dateisystem. Wenn Sie also nur love.txt bereitstellen, können Sie es separat festschreiben und dann dasselbe für cool.txt tun:

Separate Zusage (Quelle: https://youtu.be/ozA1V00GIT8)


Schön 😎

Szenario Nr. 4

Erstellen Sie eine neue Datei ( new_file.txt ) mit etwas Text und fügen Sie etwas Text zu love.txt hinzu. Stellen Sie beide Änderungen bereit und übernehmen Sie sie:

Ein neues Commit (Quelle: https://youtu.be/ozA1V00GIT8)


Ups 🙈🙈


Diesmal wollte ich also, dass es sich in einem anderen Zweig befindet, aber nicht in einem neuen Zweig, sondern in einem bereits vorhandenen Zweig.


Also was kannst du tun?


Ich gebe Ihnen einen Hinweis. Die Antwort ist wirklich kurz und wirklich einfach. Was machen wir zuerst?


Nein, nicht reset . Wir zeichnen. Das ist das Erste, was man tun sollte, da es alles andere viel einfacher machen würde. Das ist also der aktuelle Stand:

Das neue Commit auf „main“ erscheint blau (Quelle: https://youtu.be/ozA1V00GIT8)


Und der gewünschte Zustand?

Wir möchten, dass sich der „blaue“ Commit in einem anderen, „existierenden“ Zweig befindet (Quelle: https://youtu.be/ozA1V00GIT8)


Wie gelangt man vom aktuellen zum gewünschten Zustand, was wäre am einfachsten?


Eine Möglichkeit wäre also git reset wie zuvor zu verwenden, aber ich möchte, dass Sie auch eine andere Möglichkeit ausprobieren.


Verschieben Sie zunächst HEAD so, dass es auf den existing Zweig zeigt:

Wechseln Sie zum „vorhandenen“ Zweig (Quelle: https://youtu.be/ozA1V00GIT8)


Intuitiv möchten Sie die im blauen Commit eingeführten Änderungen übernehmen und diese Änderungen („Kopieren und Einfügen“) auf den existing Zweig anwenden. Und Git hat genau dafür ein Tool.


Um Git aufzufordern, die zwischen diesem Commit und seinem übergeordneten Commit eingeführten Änderungen zu übernehmen und diese Änderungen einfach auf den aktiven Zweig anzuwenden, können Sie git cherry-pick verwenden. Dieser Befehl übernimmt die in der angegebenen Revision eingeführten Änderungen und wendet sie auf das aktive Commit an.


Außerdem wird ein neues Commit-Objekt erstellt und der aktive Zweig aktualisiert, sodass er auf dieses neue Objekt verweist.

Verwendung von „git Cherry-pick“ (Quelle: https://youtu.be/ozA1V00GIT8)


Im obigen Beispiel habe ich die SHA-1-Kennung des erstellten Commits angegeben, Sie können aber auch git cherry-pick main verwenden, da der Commit, dessen Änderungen wir anwenden, derjenige ist, auf den main verweist.


Wir möchten jedoch nicht, dass diese Änderungen im main vorhanden sind. git cherry-pick hat die Änderungen nur auf den existing Zweig angewendet. Wie kann man sie aus main entfernen?


Eine Möglichkeit wäre, zurück zu main zu switch und dann git reset --hard HEAD~1 zu verwenden:

Zurücksetzen von „main“ (Quelle: https://youtu.be/ozA1V00GIT8)


Du hast es geschafft! 💪🏻


Beachten Sie, dass git cherry-pick tatsächlich die Differenz zwischen dem angegebenen Commit und seinem übergeordneten Commit berechnet und diese dann auf den aktiven Commit anwendet. Das bedeutet, dass Git diese Änderungen manchmal nicht anwenden kann, da es zu einem Konflikt kommen kann, aber das ist ein Thema für einen anderen Beitrag.


Beachten Sie außerdem, dass Sie Git bitten können, die in jedem Commit eingeführten Änderungen cherry-pick , nicht nur in Commits, auf die von einem Zweig verwiesen wird.


Wir haben ein neues Tool erworben, also haben wir sowohl git reset als auch git cherry-pick in der Tasche.

Szenario Nr. 5

Okay, also ein anderer Tag, ein anderes Repo, ein anderes Problem.


Erstellen Sie ein Commit:

Ein weiterer Commit (Quelle: https://youtu.be/ozA1V00GIT8)


Und push es auf den Remote-Server:

(Quelle: https://youtu.be/ozA1V00GIT8)


Ähm, ups 😓…


Mir ist gerade etwas aufgefallen. Da liegt ein Tippfehler vor. Ich habe This is more tezt anstelle von This is more text geschrieben. Hoppla. Was ist nun das große Problem? Ich habe ed push , was bedeutet, dass jemand anderes diese Änderungen möglicherweise bereits pull hat.


Wenn ich diese Änderungen überschreibe, indem ich git reset verwende, wie wir es bisher getan haben, werden wir unterschiedliche Historien haben, und die Hölle könnte losbrechen. Sie können Ihre eigene Kopie des Repos so oft umschreiben, wie Sie möchten, bis Sie sie push .


Sobald Sie die Änderung push , müssen Sie sehr sicher sein, dass niemand anderes diese Änderungen abgerufen hat, wenn Sie den Verlauf neu schreiben möchten.


Alternativ können Sie ein anderes Tool namens git revert verwenden. Dieser Befehl nimmt den Commit, den Sie ihm zur Verfügung stellen, und berechnet den Unterschied zum übergeordneten Commit, genau wie git cherry-pick , berechnet dieses Mal jedoch die umgekehrten Änderungen.


Wenn Sie also im angegebenen Commit eine Zeile hinzugefügt haben, würde der umgekehrte Vorgang die Zeile löschen und umgekehrt.

Mit „git revert“ die Änderungen rückgängig machen (Quelle: https://youtu.be/ozA1V00GIT8)


git revert hat ein neues Commit-Objekt erstellt, was bedeutet, dass es eine Ergänzung zum Verlauf ist. Durch die Verwendung von git revert haben Sie den Verlauf nicht neu geschrieben. Sie haben Ihren Fehler in der Vergangenheit zugegeben, und dieser Commit ist ein Eingeständnis, dass Sie einen Fehler gemacht und ihn nun behoben haben.


Manche würden sagen, es sei der ausgereiftere Weg. Einige würden sagen, dass der Verlauf nicht so sauber ist, wie wenn Sie git reset verwenden würden, um den vorherigen Commit neu zu schreiben. Aber so lässt sich vermeiden, dass die Geschichte neu geschrieben wird.


Sie können den Tippfehler jetzt beheben und erneut festschreiben:

Wiederholen der Änderungen (Quelle: https://youtu.be/ozA1V00GIT8)


Ihr Werkzeugkasten ist jetzt mit einem neuen, glänzenden Werkzeug geladen. revert :

Unsere Toolbox (Quelle: https://youtu.be/ozA1V00GIT8)


Szenario Nr. 6

Erledigen Sie Ihre Arbeit, schreiben Sie Code und fügen Sie ihn zu love.txt hinzu. Führen Sie diese Änderung durch und übernehmen Sie sie:

Ein weiterer Commit (Quelle: https://youtu.be/ozA1V00GIT8)


Ich habe das Gleiche auf meinem Computer gemacht und mit der Up auf meiner Tastatur zu den vorherigen Befehlen zurückgeblättert. Dann habe ich Enter gedrückt und … Wow.


Hoppla.

Habe ich gerade „git reset – hard“ ausgeführt? (Quelle: https://youtu.be/ozA1V00GIT8)


Habe ich gerade git reset --hard verwendet? 😨


Was ist eigentlich passiert? Git hat den Zeiger auf HEAD~1 verschoben, sodass der letzte Commit mit all meiner wertvollen Arbeit aus dem aktuellen Verlauf nicht erreichbar ist. Git hat auch alle Änderungen aus dem Staging-Bereich entfernt und dann das Arbeitsverzeichnis an den Status des Staging-Bereichs angepasst.


Das heißt, alles passt zu diesem Zustand, in dem meine Arbeit … weg ist.


Zeit zum Ausflippen. Ausrasten.

Aber gibt es wirklich einen Grund auszuflippen? Nicht wirklich... Wir sind entspannte Menschen. Was machen wir? Nun, ist der Commit intuitiv wirklich, wirklich weg? Nein Warum nicht? Es existiert immer noch in der internen Datenbank von Git.


Wenn ich nur wüsste, wo das ist, wüsste ich den SHA-1-Wert, der diesen Commit identifiziert, und wir könnten ihn wiederherstellen. Ich könnte das Rückgängigmachen sogar rückgängig machen und zu diesem Commit reset .


Das Einzige, was ich hier also wirklich brauche, ist der SHA-1 des „gelöschten“ Commits.


Die Frage ist also, wie finde ich es? Wäre git log nützlich?


Nicht wirklich. git log würde zu HEAD gehen, was auf main verweist, was auf den übergeordneten Commit des gesuchten Commits verweist. Dann würde git log Daten über die übergeordnete Kette zurückverfolgen, was den Commit nicht mit meiner wertvollen Arbeit einschließt.

„git log“ hilft in diesem Fall nicht (Quelle: https://youtu.be/ozA1V00GIT8)


Zum Glück haben die sehr klugen Leute, die Git erstellt haben, auch einen Backup-Plan für uns erstellt, und dieser heißt reflog .


Während Sie mit Git arbeiten, fügt Git jedes Mal, wenn Sie HEAD ändern, was Sie mit git reset tun können, aber auch mit anderen Befehlen wie git switch oder git checkout , einen Eintrag zum reflog hinzu.


„git reflog“ zeigt uns, wo „HEAD“ war (Quelle: https://youtu.be/ozA1V00GIT8)


Wir haben unser Engagement gefunden! Es ist das, das mit 0fb929e beginnt.


Wir können es auch anhand seines „Spitznamens“ identifizieren – HEAD@{1} . So wie Git beispielsweise HEAD~1 verwendet, um zum ersten übergeordneten Element von HEAD zu gelangen, und HEAD~2 , um auf das zweite übergeordnete Element von HEAD zu verweisen, usw., verwendet Git HEAD@{1} , um auf das erste Reflog-übergeordnete Element von HEAD zu verweisen. wo HEAD im vorherigen Schritt gezeigt hat.


Wir können git rev-parse auch bitten, uns seinen Wert zu zeigen:

(Quelle: https://youtu.be/ozA1V00GIT8)


Eine andere Möglichkeit, das reflog anzuzeigen, ist die Verwendung von git log -g , wodurch git log aufgefordert wird, das reflog tatsächlich zu berücksichtigen:

Die Ausgabe von „git log -g“ (Quelle: https://youtu.be/ozA1V00GIT8)


Wir sehen oben, dass reflog ebenso wie HEAD auf main verweist, was auf „Commit 2“ verweist. Aber das übergeordnete Element dieses Eintrags im reflog verweist auf „Commit 3“.


Um also zu „Commit 3“ zurückzukehren, können Sie einfach git reset --hard HEAD@{1} (oder den SHA-1-Wert von „Commit 3“) verwenden:

(Quelle: https://youtu.be/ozA1V00GIT8)


Und jetzt, wenn wir git log :

Unsere Geschichte ist zurück!!! (Quelle: https://youtu.be/ozA1V00GIT8)


Wir haben den Tag gerettet! 🎉👏🏻


Was würde passieren, wenn ich diesen Befehl erneut verwenden würde? Und git commit --reset HEAD@{1} ausgeführt? Git würde HEAD auf die Stelle setzen, auf HEAD vor dem letzten reset zeigte, also auf „Commit 2“. Wir können den ganzen Tag weitermachen:

(Quelle: https://youtu.be/ozA1V00GIT8)


Wenn Sie sich jetzt unsere Toolbox ansehen, ist sie voller Tools, die Ihnen bei der Lösung vieler Fälle helfen können, in denen in Git etwas schief geht:

Unser Werkzeugkasten ist ziemlich umfangreich! (Quelle: https://youtu.be/ozA1V00GIT8)


Mit diesen Tools verstehen Sie jetzt besser, wie Git funktioniert. Es gibt weitere Tools, mit denen Sie den Verlauf gezielt umschreiben können ( git rebase ), aber Sie haben in diesem Beitrag bereits viel gelernt. In zukünftigen Beiträgen werde ich mich auch mit git rebase befassen.


Das wichtigste Werkzeug, noch wichtiger als die fünf in dieser Toolbox aufgeführten Werkzeuge, ist das Whiteboarden der aktuellen Situation im Vergleich zur gewünschten. Vertrauen Sie mir, dadurch wird jede Situation weniger entmutigend und die Lösung klarer.

Erfahren Sie mehr über Git

Ich habe auch einen Live-Vortrag über den Inhalt dieses Beitrags gehalten. Wenn Sie ein Video bevorzugen (oder es neben der Lektüre ansehen möchten), können Sie es finden .


Allgemein, mein YouTube-Kanal deckt viele Aspekte von Git und seinen Interna ab; Sie sind herzlich willkommen Hör zu (Wortspiel beabsichtigt 😇)

Über den Autor

Omer Rosenbaum ist CTO und Mitbegründer von Schwimmen , ein Entwicklungstool, das Entwicklern und ihren Teams hilft, Wissen über ihre Codebasis mit aktueller interner Dokumentation zu verwalten. Omer ist der Gründer der Check Point Security Academy und war Cyber Security Lead bei ITC, einer Bildungsorganisation, die talentierte Fachkräfte für Karrieren im Technologiebereich ausbildet.


Omer hat einen MA in Linguistik von der Universität Tel Aviv und ist der Schöpfer des Kurzer YouTube-Kanal .


Erstveröffentlichung hier