it-swarm.com.de

Wie kann ich mehrere Git-Commits wiederherstellen?

Ich habe ein Git-Repository, das so aussieht:

A -> B -> C -> D -> HEAD

Ich möchte, dass der Kopf des Zweigs auf A zeigt, d. H. Ich möchte, dass B, C, D und HEAD verschwinden, und ich möchte, dass der Kopf synonym mit A ist.

Es hört sich so an, als ob ich entweder versuchen kann, die Datenbank neu zu gründen (trifft nicht zu, da ich die Änderungen dazwischen verschoben habe) oder zurückkehren kann. Aber wie kann ich mehrere Commits wiederherstellen? Kann ich nacheinander zurücksetzen? Ist die Reihenfolge wichtig?

821
Bill

Erweitern, was ich in einem Kommentar geschrieben habe

Die allgemeine Regel ist, dass Sie die von Ihnen veröffentlichte Historie nicht umschreiben (ändern) sollten, da jemand möglicherweise seine Arbeit darauf basiert hat. Wenn Sie den Verlauf neu schreiben (ändern), treten Probleme beim Zusammenführen der Änderungen und beim Aktualisieren auf.

Die Lösung besteht also darin, ein neues Commit zu erstellen, das Änderungen rückgängig macht, das Sie entfernen möchten. Sie können dies mit dem Befehl git revert tun.

Sie haben folgende Situation:

 A <- B <- C <- D <- Master <- HEAD 

(Pfeile beziehen sich hier auf die Richtung des Zeigers: die "Eltern" -Referenz im Fall von Festschreibungen, die obere Festschreibung im Fall von Verzweigungskopf (Verzweigungsreferenz) und der Name der Verzweigung im Fall von HEAD Referenz).

Was Sie erstellen müssen, ist Folgendes:

 A <- B <- C <- D <- [(BCD) ^ - 1] <- Master <- HEAD 

wobei "[(BCD) ^ - 1]" die Festschreibung bedeutet, die Änderungen in den Festschreibungen B, C, D rückgängig macht. Die Mathematik sagt uns, dass (BCD) ^ - 1 = D ^ -1 C ^ -1 B ^ -1, also Sie können die erforderliche Situation mit den folgenden Befehlen abrufen:

$ git revert --no-commit D
$ git revert --no-commit C
$ git revert --no-commit B
$ git commit -m "the commit message"

Eine alternative Lösung wäre: checkout Inhalt von Festschreiben A und Festschreiben dieses Zustands:

$ git checkout -f A -- .
$ git commit -a

Dann hätten Sie folgende Situation:

 A <- B <- C <- D <- A '<- master <- HEAD 

Das Festschreiben A 'hat den gleichen Inhalt wie Festschreiben A, ist jedoch ein anderes Festschreiben (Festschreibungsnachricht, Eltern, Festschreibungsdatum).

Die Lösung von Jeff Ferland, modifiziert von Charles Bailey baut auf der gleichen Idee auf, verwendet aber git reset :

$ git reset --hard A
$ git reset --soft @{1}  # (or ORIG_HEAD), which is D
$ git commit
1163
Jakub Narębski

Dazu müssen Sie nur den Befehl Zurücksetzen verwenden und den Bereich der Festschreibungen angeben, die zurückgesetzt werden sollen.

Unter Berücksichtigung Ihres Beispiels müssten Sie dies tun (vorausgesetzt, Sie befinden sich auf dem Zweig 'master'):

git revert master~3..master

Dadurch wird in Ihrem lokalen System ein neues Commit mit dem umgekehrten Commit von B, C und D erstellt (was bedeutet, dass die durch diese Commits eingeführten Änderungen rückgängig gemacht werden):

A <- B <- C <- D <- BCD' <- HEAD
200
Victor

Sauberer Weg was ich nützlich fand

git revert --no-commit HEAD~3..

Dieser Befehl setzt die letzten drei Festschreibungen mit nur einer Festschreibung zurück.

Auch schreibt Geschichte nicht um.

164
deepdive

Ähnlich wie bei der Antwort von Jakub können Sie so einfach aufeinanderfolgende Commits auswählen, die wiederhergestellt werden sollen.

# revert all commits from B to HEAD, inclusively
$ git revert --no-commit B..HEAD  
$ git commit -m 'message'
62
konyak
git reset --hard a
git reset --mixed d
git commit

Das wird für alle auf einmal ein Rückfall sein. Geben Sie eine gute Commit-Nachricht.

54
Jeff Ferland

Stellen Sie zunächst sicher, dass Ihre Arbeitskopie nicht geändert wurde. Dann:

git diff HEAD commit_sha_you_want_to_revert_to | git apply

und dann einfach festschreiben. Vergessen Sie nicht zu dokumentieren, was der Grund für die Rücknahme ist.

35
mateusz.fiolka

Ich bin so frustriert, dass diese Frage nicht einfach beantwortet werden kann. Bei jeder anderen Frage geht es darum, wie man richtig zurückkehrt und die Geschichte bewahrt. Diese Frage lautet "Ich möchte, dass der Kopf des Zweigs auf A zeigt, dh ich möchte, dass B, C, D und HEAD verschwinden = und ich möchte, dass der Kopf gleichbedeutend mit A ist. "

git checkout <branch_name>
git reset --hard <commit Hash for A>
git Push -f

Ich habe viel gelernt, als ich Jakubs Post gelesen habe, aber ein Mitarbeiter der Firma (mit Zugriff auf Push auf unsere "Testing" -Zweigstelle ohne Pull-Request) hat wie 5 schlechte Commits gepusht, um einen Fehler zu beheben, den er vor 5 Commits gemacht hat. Nicht nur das, sondern ein oder zwei Pull-Requests wurden akzeptiert, die jetzt schlecht waren. Also vergiss es, ich fand das letzte gute Commit (abc1234) und führte einfach das grundlegende Skript aus:

git checkout testing
git reset --hard abc1234
git Push -f

Ich sagte den anderen 5 Jungs, die in diesem Repo arbeiten, dass sie sich ihre Änderungen in den letzten Stunden und Wipe/Re-Branch aus den letzten Tests besser notieren sollten. Das Ende der Geschichte.

26
Suamere

Dies ist eine Erweiterung einer der Lösungen in Jakubs Antwort

Ich war mit einer Situation konfrontiert, in der die Commits, die ich zurücksetzen musste, etwas komplex waren. Einige der Commits waren Merge-Commits, und ich musste vermeiden, den Verlauf neu zu schreiben. Ich konnte eine Reihe von git revert -Befehlen nicht verwenden, da ich schließlich auf Konflikte zwischen den hinzugefügten Umkehrungsänderungen gestoßen bin. Ich habe die folgenden Schritte ausgeführt.

Überprüfen Sie zunächst den Inhalt des Ziel-Commits, während Sie HEAD am Ende des Zweigs belassen:

$ git checkout -f <target-commit> -- .

(Das - stellt sicher, dass <target-commit> als Festschreibung und nicht als Datei interpretiert wird; das. Verweist auf das aktuelle Verzeichnis.)

Bestimmen Sie dann, welche Dateien zu den zurückgesetzten Commits hinzugefügt wurden und daher gelöscht werden müssen:

$ git diff --name-status --cached <target-commit>

Dateien, die hinzugefügt wurden, sollten am Anfang der Zeile mit einem "A" angezeigt werden, und es sollten keine weiteren Unterschiede bestehen. Wenn nun Dateien entfernt werden müssen, stellen Sie diese Dateien zum Entfernen bereit:

$ git rm <filespec>[ <filespec> ...]

Führen Sie zum Schluss die Umkehrung durch:

$ git commit -m 'revert to <target-commit>'

Wenn gewünscht, stellen Sie sicher, dass wir wieder in dem gewünschten Zustand sind:

$git diff <target-commit> <current-commit>

Es sollte keine Unterschiede geben.

8
Warren Dew

Die einfache Möglichkeit, eine Gruppe von Commits in einem gemeinsam genutzten Repository wiederherzustellen (das Benutzer verwenden und das Sie beibehalten möchten), besteht darin, git revert in Verbindung mit git rev-list zu verwenden. Der letztere wird Ihnen eine Liste von Commits zur Verfügung stellen, der erstere wird das Zurücksetzen selbst vornehmen.

Dafür gibt es zwei Möglichkeiten. Wenn Sie möchten, dass mehrere Commits in einem einzigen Commit wiederhergestellt werden, gehen Sie wie folgt vor:

for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert -n $i; done

dadurch wird eine Gruppe von Commits zurückgesetzt, die Sie benötigen. Lassen Sie jedoch alle Änderungen in Ihrem Arbeitsbaum, und Sie sollten sie alle wie gewohnt festschreiben.

Eine andere Möglichkeit ist, eine einzelne Festschreibung pro rückgängig gemachter Änderung vorzunehmen:

for i in `git rev-list <first-commit-sha>^..<last-commit-sha>`; do git revert --no-edit -s $i; done

Zum Beispiel, wenn Sie einen Commit-Baum wie haben

 o---o---o---o---o---o--->    
fff eee ddd ccc bbb aaa

um die Änderungen von eee zu bbb rückgängig zu machen, führen Sie aus

for i in `git rev-list eee^..bbb`; do git revert --no-edit -s $i; done
3
Ruslan Kabalin

Meiner Meinung nach könnte ein sehr einfacher und sauberer Weg sein:

gehe zurück zu A

git checkout -f A

zeigen Sie den Kopf des Meisters auf den aktuellen Status

git symbolic-ref HEAD refs/heads/master

sparen

git commit
0
nulll