Kann ich eine teilweise Wiederherstellung in GIT durchführen?

156

Ist es möglich, nur eine einzelne Datei oder bestimmte Änderungen in einer Datei beim Festschreiben mehrerer Dateien zurückzusetzen?

Ganze Geschichte Ich habe eine Reihe von Dateien festgeschrieben. Eine Reihe von Commits später hat jemand, der namenlos bleibt (JACK !!!), eine Datei in sein Repository kopiert und mehrere Dateien festgeschrieben, wobei einige der von mir vorgenommenen Änderungen überschrieben wurden. Ich möchte die eine Datei zurücksetzen, die überlastet wurde oder noch besser, gehen Sie hinein und setzen Sie zwei Änderungen in dieser Datei zurück. Dies muss ein separates Revert-Commit sein, da es gezogen und gedrückt wurde.

Kupplung
quelle
Brian hat mich auf den richtigen Weg gebracht. Am Ende habe ich git add --patch verwendet und dann die Bearbeitungsfunktion innerhalb des Patches verwendet, um das zu bekommen, was ich wollte.
Kupplung
2
Ich bin ziemlich spät dran, aber ich glaube, ich habe die "richtige" Antwort gefunden .
ntc2
@ ntc2 Seltsamerweise funktionierte die akzeptierte Antwort für mich viel besser als die von Ihnen verknüpfte - sie führte zu Zusammenführungskonflikten, die ich lösen konnte, anstatt nur keine Patches anzuwenden.
Freitag,
@liridayn Hast du meine ganze Antwort gelesen? Im Abschnitt "Variationen" behaupte ich, dass das Hinzufügen --3wayzu Zusammenführungskonflikten führt, anstatt Patches nicht anzuwenden.
Ntc2

Antworten:

204

Sie können das Commit zurücksetzen, ohne ein neues zu erstellen, indem Sie die Option '--no-commit' hinzufügen. Dadurch bleiben alle zurückgesetzten Dateien im Staging-Bereich. Von dort aus würde ich einen Soft-Reset durchführen und die Änderungen hinzufügen, die ich wirklich wollte. Ein Beispiel für einen Workflow:

git revert <sha-of-bad-commit> --no-commit
git reset   // This gets them out of the staging area
<edit bad file to look like it should, if necessary>
git add <bad-file>
git checkout . // This wipes all the undesired reverts still hanging around in the working copy
git commit
bobDevil
quelle
42
Nach dem Soft-Reset können Sie auch git add -peine interaktive Sitzung starten, in der Sie selektiv Dateiblöcke anstelle ganzer Dateien hinzufügen können. (Es gibt auch git reset -pselektiv Änderungen auf der Bühne zu entfernen. Gut zu wissen, aber wahrscheinlich nicht, was Sie in diesem Szenario wollen.)
Stéphan Kochen
1
Dies war genau das, wonach ich gesucht habe: In Arbeitskopie zurückkehren, Hunks interaktiv auswählen, festschreiben. Sie verdienen einen großen, salzigen Mann-Knutschfleck dafür: *
das_weezul
Eine weitere Lösung , die durch diesen inspiriert wäre revert, reset, stash -p(Stash „bricht , dass ich will nicht zu actualy make“), addder Rest,commit
Cyril CHAPON
82

Mit dem checkoutBefehl können Sie die alte Version einer Datei interaktiv anwenden .

Wenn Sie beispielsweise wissen, COMMITwo der wieder hinzuzufügende Code entfernt wurde, können Sie den folgenden Befehl ausführen:

git checkout -p COMMIT^ -- FILE_TO_REVERT

Git fordert Sie auf, die in der aktuellen Version der Datei fehlenden Hunks wieder hinzuzufügen. Sie können eeinen Patch der Änderung erstellen, bevor Sie ihn erneut anwenden.

cmcginty
quelle
Sehr nützlich, wenn Sie nur einen Teil der Datei zurücksetzen möchten! Grundsätzlich, um Brocken vom Kopf zu bekommen,git checkout -p path/to/file
Falstaff
40

Sie können den alten, guten Inhalt der Dateien, mit denen Sie zurückkehren möchten, einfach manuell auschecken git checkout. Wenn Sie beispielsweise my-important-filezu der Version zurückkehren möchten, die in der Version enthalten war abc123, können Sie dies tun

git checkout abc123 -- my-important-file

Jetzt haben Sie den alten Inhalt von my-important-fileback und können ihn sogar bearbeiten, wenn Sie möchten, und wie gewohnt ein Commit durchführen, um ein Commit durchzuführen, das die von ihm vorgenommenen Änderungen rückgängig macht. Wenn es nur einige Teile seines Commits gibt, die Sie zurücksetzen möchten, git add -pwählen Sie mit nur einige Hunks aus dem Patch aus, den Sie festschreiben.

Brian Campbell
quelle
19
Dies ist keine revert, Sie nehmen nur eine alte Version der Datei zurück. Ein ordnungsgemäßer revertBefehl entfernt die fehlerhaften Festschreibungsänderungen in der Datei, auch wenn sie seit diesem fehlerhaften Festschreiben mehrmals geändert wurden, und Sie möchten diese Änderungen nicht verlieren .
Totor
2
Totor, siehe meine Antwort. Sie können '-p' verwenden, um Änderungen zu speichern. Die Antwort ist dieser sehr nahe.
cmcginty
1
Oder Sie können dies kombinieren git checkout -p.
Léo Lam
30

Ich habe einen Weg gefunden, dies auf der Git-Mailingliste zu tun:

git show <commit> -- <path> | git apply --reverse

Quelle: http://git.661346.n2.nabble.com/Revert-a-single-commit-in-a-single-file-td6064050.html#a6064406

Variationen

Dieser Befehl schlägt fehl (verursacht keine Änderungen), wenn der Patch nicht sauber --3wayangewendet wird , sondern stattdessen Konflikte auftreten, die Sie dann manuell lösen können (in diesem Fall ist Caseys Antwort möglicherweise praktischer):

git show <commit> -- <path> | git apply --reverse --3way

Sie können dies auch verwenden, um mehrere Commits teilweise zurückzusetzen, z.

git log -S<string> --patch | git apply --reverse

um Dateien mit Änderungen zurückzusetzen, die <string>in einem Commit übereinstimmen . Dies ist genau das, was ich in meinem Anwendungsfall brauchte (einige separate Commits führten ähnliche Änderungen an verschiedenen Dateien ein, zusammen mit Änderungen anderer Dateien auf nicht verwandte Weise, die ich nicht zurücksetzen wollte).

Wenn Sie in festgelegt haben diff.noprefix=true, ~/.gitconfigmüssen Sie -p0dem git applyBefehl hinzufügen , z

git show <commit> -- <path> | git apply -p0 --reverse
ntc2
quelle
Diese Antwort ist viel besser als die akzeptierte: "Noch besser, gehen Sie hinein und setzen Sie zwei Änderungen in dieser Datei zurück".
Umgeschrieben am
Ich wollte nur einen Teil eines Commits zurücksetzen , also habe ich: (1) git show ... > foo.txt (2) bearbeitet foo.txt, um die Unterschiede zu entfernen, die ich nicht zurücksetzen wollte (3) git apply --reverse foo.txt , um die noch aufgelisteten Unterschiede zurückzusetzen foo.txt.
cxw
Das Hinzufügen von --binary --full-index zum Git-Show-Teil könnte ebenfalls eine nützliche Variante sein
Laurynas Biveinis