Git Reset vs. Revert vs. Rebase

In diesem Artikel lernen Sie verschiedene Möglichkeiten kennen, mit Commits in Git herumzuspielen.

Als Entwickler würden Sie solche Situationen mehrmals erleben, in denen Sie zu einem Ihrer vorherigen Commits zurückkehren wollten, aber nicht sicher sind, wie Sie das tun sollen. Und selbst wenn Sie die Git-Befehle wie reset, revert, rebase kennen, sind Ihnen die Unterschiede zwischen ihnen nicht bewusst. Fangen wir also an und verstehen, was Git Reset, Revert und Rebase sind.

Git-Reset

Git reset ist ein komplexer Befehl und wird verwendet, um die Änderungen rückgängig zu machen.

Sie können sich git reset als eine Rollback-Funktion vorstellen. Mit git reset können Sie zwischen verschiedenen Commits springen. Es gibt drei Modi zum Ausführen eines Git-Reset-Befehls: –soft, –mixed und –hard. Standardmäßig verwendet der Befehl git reset den gemischten Modus. In einem Git-Reset-Workflow kommen drei interne Verwaltungsmechanismen von Git ins Spiel: HEAD, Staging-Bereich (Index) und das Arbeitsverzeichnis.

Das Arbeitsverzeichnis ist der Ort, an dem Sie gerade arbeiten, es ist der Ort, an dem Ihre Dateien vorhanden sind. Mit einem git status-Befehl können Sie sehen, welche Dateien/Ordner im Arbeitsverzeichnis vorhanden sind.

Der Staging-Bereich (Index) ist der Ort, an dem Git alle Änderungen in den Dateien verfolgt und speichert. Die gespeicherten Änderungen werden im .git-Verzeichnis wiedergegeben. Sie verwenden git add „filename“, um die Datei zum Staging-Bereich hinzuzufügen. Und wie zuvor sehen Sie beim Ausführen von git status, welche Dateien im Staging-Bereich vorhanden sind.

Der aktuelle Zweig in Git wird als HEAD bezeichnet. Es zeigt auf den letzten Commit, der im aktuellen Checkout-Zweig stattfand. Es wird als Zeiger für jede Referenz behandelt. Sobald Sie in eine andere Verzweigung auschecken, bewegt sich der HEAD ebenfalls in die neue Verzweigung.

Lassen Sie mich erklären, wie git reset im harten, weichen und gemischten Modus funktioniert. Der harte Modus wird verwendet, um zum angegebenen Commit zu wechseln, das Arbeitsverzeichnis wird mit Dateien dieses Commits gefüllt und der Staging-Bereich wird zurückgesetzt. Beim Soft-Reset wird nur der Zeiger auf das angegebene Commit geändert. Die Dateien aller Commits verbleiben vor dem Zurücksetzen im Arbeitsverzeichnis und im Staging-Bereich. Im gemischten Modus (Standard) werden sowohl der Zeiger als auch der Bereitstellungsbereich zurückgesetzt.

Git hart zurücksetzen

Der Zweck des Git-Hard-Resets besteht darin, den HEAD zum angegebenen Commit zu verschieben. Es werden alle Commits entfernt, die nach dem angegebenen Commit stattgefunden haben. Dieser Befehl ändert den Commit-Verlauf und zeigt auf den angegebenen Commit.

In diesem Beispiel füge ich drei neue Dateien hinzu, übertrage sie und führe dann einen Hard-Reset durch.

Wie Sie dem folgenden Befehl entnehmen können, gibt es im Moment nichts zu übergeben.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.

(use "git push" to publish your local commits)

nothing to commit, working tree clean

Jetzt werde ich 3 Dateien erstellen und etwas Inhalt hinzufügen.

$ vi file1.txt
$ vi file2.txt
$ vi file3.txt

Fügen Sie diese Dateien dem vorhandenen Repository hinzu.

$ git add file*

Wenn Sie den Statusbefehl erneut ausführen, werden die neuen Dateien angezeigt, die ich gerade erstellt habe.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.

(use "git push" to publish your local commits)

Changes to be committed:

(use "git restore --staged <file>..." to unstage)

new file:
file1.txt

new file:
file2.txt

new file:
file3.txt

Lassen Sie mich Ihnen vor dem Commit zeigen, dass ich derzeit ein Protokoll mit 3 Commits in Git habe.

$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Jetzt werde ich mich an das Repository binden.

$ git commit -m 'added 3 files'
[master d69950b] added 3 files
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt

Wenn ich ls-Dateien mache, sehen Sie, dass die neuen Dateien hinzugefügt wurden.

$ git ls-files
demo
dummyfile
newfile
file1.txt
file2.txt
file3.txt

Wenn ich den log-Befehl in Git ausführe, habe ich 4 Commits und der HEAD zeigt auf den neuesten Commit.

$ git log --oneline
d69950b (HEAD -> master) added 3 files
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Wenn ich die file1.txt manuell lösche und einen Git-Status mache, wird die Meldung angezeigt, dass die Änderungen nicht zum Commit bereitgestellt werden.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

Changes not staged for commit:

(use "git add/rm <file>..." to update what will be committed)

(use "git restore <file>..." to discard changes in working directory)

deleted:
file1.txt

no changes added to commit (use "git add" and/or "git commit -a")

Jetzt führe ich den Hard-Reset-Befehl aus.

$ git reset --hard
HEAD is now at d69950b added 3 files

Wenn ich den Status erneut überprüfe, werde ich feststellen, dass es nichts zu übergeben gibt und die von mir gelöschte Datei wieder in das Repository gelangt ist. Das Rollback ist passiert, weil ich nach dem Löschen der Datei kein Commit ausgeführt habe, sodass sie nach einem Hard-Reset wieder in den vorherigen Zustand zurückgekehrt ist.

$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

nothing to commit, working tree clean

Wenn ich das Protokoll von Git überprüfe, sieht es so aus.

$ git log
commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 19:53:31 2020 +0530

added 3 files

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Der Zweck des Hard-Resets besteht darin, auf das angegebene Commit zu verweisen und das Arbeitsverzeichnis und den Staging-Bereich zu aktualisieren. Lassen Sie mich Ihnen noch ein Beispiel zeigen. Derzeit sieht die Visualisierung meiner Commits wie folgt aus:

  Was ist das, seine Vorteile und MCM-Software, die Sie in Betracht ziehen sollten

Hier werde ich den Befehl mit HEAD^ ausführen, was bedeutet, dass ich auf den vorherigen Commit zurücksetzen möchte (ein Commit zurück).

$ git reset --hard HEAD^
HEAD is now at 0db602e one more commit

Sie können sehen, dass sich der Head-Zeiger jetzt von d69950b auf 0db602e geändert hat.

$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Wenn Sie das Protokoll überprüfen, ist der Commit von d69950b weg und der Kopf zeigt jetzt auf 0db602e SHA.

$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

Test

Wenn Sie die ls-Dateien ausführen, können Sie sehen, dass sich file1.txt, file2.txt und files3.txt nicht mehr im Repository befinden, da dieser Commit und seine Datei nach dem Hard-Reset entfernt wurden.

$ git ls-files
demo
dummyfile
newfile

Git-Soft-Reset

In ähnlicher Weise zeige ich Ihnen jetzt ein Beispiel für einen Soft-Reset. Bedenken Sie, ich habe die 3 Dateien wie oben erwähnt erneut hinzugefügt und festgeschrieben. Das Git-Protokoll wird wie unten gezeigt angezeigt. Sie können sehen, dass „Soft Reset“ mein neuestes Commit ist, und HEAD weist auch darauf hin.

$ git log --oneline
aa40085 (HEAD -> master) soft reset
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Details des Commit im Protokoll können mit dem folgenden Befehl angezeigt werden.

$ git log
commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 21:01:36 2020 +0530

soft reset

commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Jetzt möchte ich mit dem Soft-Reset zu einem der älteren Commits mit SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14 wechseln

Dazu führe ich den folgenden Befehl aus. Sie müssen mehr als 6 Startzeichen von SHA übergeben, das vollständige SHA ist nicht erforderlich.

$ git reset --soft 0db602e085a4

Wenn ich jetzt das Git-Protokoll ausführe, kann ich sehen, dass HEAD auf das von mir angegebene Commit zurückgesetzt wurde.

$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <[email protected]>
Date:
Mon May 17 01:04:13 2020 +0530

one more commit

commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:54:53 2020 +0530

new commit

commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <[email protected]>
Date:
Mon May 17 00:16:33 2020 +0530

test

Aber der Unterschied hier ist, dass die Dateien des Commit (aa400858aab3927e79116941c715749780a59fc9), wo ich 3 Dateien hinzugefügt hatte, immer noch in meinem Arbeitsverzeichnis sind. Sie wurden nicht gelöscht. Aus diesem Grund sollten Sie eher einen Soft-Reset als einen Hard-Reset verwenden. Es besteht keine Gefahr, dass die Dateien im Soft-Modus verloren gehen.

$ git ls-files
demo
dummyfile
file1.txt
file2.txt
file3.txt
newfile

Git-Revert

In Git wird der Revert-Befehl verwendet, um eine Revert-Operation durchzuführen, dh einige Änderungen rückgängig zu machen. Es ähnelt dem Reset-Befehl, aber der einzige Unterschied besteht darin, dass Sie ein neues Commit ausführen, um zu einem bestimmten Commit zurückzukehren. Kurz gesagt, es ist fair zu sagen, dass der Befehl git revert ein Commit ist.

  Sling TV-Fehler 4 310 behoben

Der Git-Revert-Befehl löscht keine Daten, während der Wiederherstellungsvorgang ausgeführt wird.

Nehmen wir an, ich füge 3 Dateien hinzu und führe eine Git-Commit-Operation für das Revert-Beispiel aus.

$ git commit -m 'add 3 files again'
[master 812335d] add 3 files again
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt

Das Protokoll zeigt den neuen Commit an.

$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Nun möchte ich auf einen meiner früheren Commits zurückgreifen, sagen wir – „59c86c9 new commit“. Ich würde den folgenden Befehl ausführen.

$ git revert 59c86c9

Dadurch wird eine Datei geöffnet, Sie finden die Details des Commits, zu dem Sie zurückkehren möchten, und Sie können Ihrem neuen Commit hier einen Namen geben und dann die Datei speichern und schließen.

Revert "new commit"

This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323.

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: dummyfile

Nachdem Sie die Datei gespeichert und geschlossen haben, erhalten Sie diese Ausgabe.

$ git revert 59c86c9
[master af72b7a] Revert "new commit"
1 file changed, 1 insertion(+), 1 deletion(-)

Um nun die notwendigen Änderungen vorzunehmen, hat revert im Gegensatz zu reset einen weiteren neuen Commit durchgeführt. Wenn Sie das Protokoll erneut überprüfen, finden Sie aufgrund der Wiederherstellungsoperation einen neuen Commit.

$ git log --oneline
af72b7a (HEAD -> master) Revert "new commit"
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Das Git-Protokoll enthält den gesamten Verlauf der Commits. Wenn Sie die Commits aus der History entfernen möchten, dann ist revert keine gute Wahl, aber wenn Sie die Commit-Änderungen in der History beibehalten wollen, dann ist revert statt reset der geeignete Befehl.

Git-Rebase

In Git ist Rebase die Möglichkeit, Commits eines Zweigs über einen anderen zu verschieben oder zu kombinieren. Als Entwickler würde ich meine Features in einem realen Szenario nicht auf dem Master-Branch erstellen. Ich würde an meinem eigenen Branch (einem „Feature-Branch“) arbeiten, und wenn ich ein paar Commits in meinem Feature-Branch mit dem hinzugefügten Feature habe, würde ich es dann gerne in den Master-Branch verschieben.

Rebase kann manchmal etwas verwirrend sein, da es einem Merge sehr ähnlich ist. Das Ziel der Zusammenführung und Rebasierung beider ist es, die Commits aus meinem Feature-Branch zu nehmen und sie in einen Master-Branch oder einen anderen Branch zu legen. Betrachten Sie, ich habe ein Diagramm, das so aussieht:

  Erstellen Sie Ihre nächste App mit diesen Open Source Low-Code/No-Code-Plattformen

Angenommen, Sie arbeiten in einem Team mit anderen Entwicklern. In diesem Fall können Sie sich vorstellen, dass dies sehr komplex werden könnte, wenn eine Reihe anderer Entwickler an verschiedenen Feature-Zweigen arbeiten und diese mehrere Änderungen zusammengeführt haben. Es wird verwirrend zu verfolgen.

Also, hier wird Rebase helfen. Dieses Mal werde ich, anstatt einen Git-Merge durchzuführen, einen Rebase durchführen, bei dem ich meine beiden Feature-Branch-Commits nehmen und sie in den Master-Branch verschieben möchte. Ein Rebase nimmt alle meine Commits aus dem Feature-Branch und verschiebt sie auf die Master-Branch-Commits. Hinter den Kulissen dupliziert Git also die Feature-Branch-Commits auf dem Master-Branch.

Mit diesem Ansatz erhalten Sie ein sauberes geradliniges Diagramm mit allen Commits in einer Reihe.

Es macht es einfach nachzuvollziehen, welche Commits wohin gegangen sind. Sie können sich vorstellen, wenn Sie in einem Team mit vielen Entwicklern sind, sind alle Commits immer noch hintereinander. Es ist also wirklich einfach zu folgen, selbst wenn viele Leute gleichzeitig an demselben Projekt arbeiten.

Lassen Sie mich Ihnen das praktisch zeigen.

So sieht mein Master-Branch derzeit aus. Es hat 4 Commits.

$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Ich werde den folgenden Befehl ausführen, um einen neuen Zweig namens Feature zu erstellen und zu ihm zu wechseln, und dieser Zweig wird aus dem 2. Commit erstellt, dh 59c86c9

(master)
$ git checkout -b feature 59c86c9
Switched to a new branch 'feature'

Wenn Sie das Protokoll im Feature-Branch überprüfen, kommen nur 2 Commits vom Master (Mainline).

(feature)
$ git log --oneline
59c86c9 (HEAD -> feature) new commit
e2f44fc (origin/master, origin/HEAD) test

Ich werde Feature 1 erstellen und es dem Feature-Branch zuweisen.

(feature)
$ vi feature1.txt

(feature)
$ git add .
The file will have its original line endings in your working directory

(feature)
$ git commit -m 'feature 1'
[feature c639e1b] feature 1
1 file changed, 1 insertion(+)
create mode 100644 feature1.txt

Ich werde ein weiteres Feature, dh Feature 2, im Feature-Zweig erstellen und festschreiben.

(feature)
$ vi feature2.txt

(feature)
$ git add .
The file will have its original line endings in your working directory

(feature)
$ git commit -m 'feature 2'
[feature 0f4db49] feature 2
1 file changed, 1 insertion(+)
create mode 100644 feature2.txt

Wenn Sie nun das Protokoll des Feature-Zweigs überprüfen, enthält er zwei neue Commits, die ich oben ausgeführt habe.

(feature)
$ git log --oneline
0f4db49 (HEAD -> feature) feature 2
c639e1b feature 1
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Jetzt möchte ich diese beiden neuen Features zum Master-Zweig hinzufügen. Dafür verwende ich den rebase-Befehl. Aus dem Feature-Branch werde ich gegen den Master-Branch rebasen. Dadurch wird mein Feature-Zweig gegen die neuesten Änderungen neu verankert.

(feature)
$ git rebase master
Successfully rebased and updated refs/heads/feature.

Jetzt werde ich weitermachen und den Master-Zweig auschecken.

(feature)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.

(use "git push" to publish your local commits)

Und schließlich rebasiere den Master-Branch gegen meinen Feature-Branch. Dadurch werden diese beiden neuen Commits in meinem Feature-Zweig übernommen und auf meinem Master-Zweig wiedergegeben.

(master)
$ git rebase feature
Successfully rebased and updated refs/heads/master.

Wenn ich jetzt das Protokoll im Master-Branch überprüfe, kann ich sehen, dass die beiden Commits meines Features-Branch erfolgreich zu meinem Master-Branch hinzugefügt wurden.

(master)
$ git log --oneline
766c996 (HEAD -> master, feature) feature 2
c036a11 feature 1
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test

Das war alles über Reset-, Revert- und Rebase-Befehle in Git.

Fazit

Das war alles über Reset-, Revert- und Rebase-Befehle in Git. Ich hoffe, diese Schritt-für-Schritt-Anleitung war hilfreich. Jetzt wissen Sie, wie Sie mit Ihren Commits nach Bedarf herumspielen können, indem Sie die im Artikel erwähnten Befehle verwenden.