Machen Sie einen Teil der nicht bereitgestellten Änderungen in Git rückgängig

157

Wie mache ich Teile meiner nicht bereitgestellten Änderungen in Git rückgängig, aber behalte den Rest als nicht bereitgestellt? Ich habe Folgendes herausgefunden:

git commit --interactive
# Choose the parts I want to delete
# Commit the changes
git stash
git rebase -i master # (I am an ancestor of master)
# Delete the line of the most recent commit
git stash apply

Das funktioniert, aber es wäre schön, wenn es so etwas wie git commit --interactivenur zum Zurücksetzen von Änderungen gäbe . Irgendwelche besseren Methoden?

asmeurer
quelle

Antworten:

264

Sie können verwenden git checkout -p, um einzelne Hunks aus dem Unterschied zwischen Ihrer Arbeitskopie und dem Index zum Zurücksetzen auszuwählen. Ebenso git add -pkönnen Sie Hunks auswählen, die dem Index hinzugefügt werden sollen, und git reset -pSie können einzelne Hunks aus dem Unterschied zwischen Index und HEAD auswählen, um aus dem Index auszusteigen.

$ git checkout -p file/to/partially/revert
# or ...
$ git checkout -p .

Wenn Sie Ihr Git-Repository vorab als Snapshot erstellen möchten, um diese Änderungen vor dem Zurücksetzen beizubehalten, gehe ich wie folgt vor:

$ git stash; git stash apply

Wenn Sie das häufig verwenden, möchten Sie es möglicherweise als Alias ​​verwenden:

[alias]
    checkpoint = !git stash; git stash apply

Das Zurücksetzen einzelner Hunks oder Zeilen kann noch einfacher sein, wenn Sie einen guten Editor-Modus oder ein Plugin verwenden, das möglicherweise die Auswahl von Zeilen unterstützt, die direkt zurückgesetzt werden sollen, da -pdie Verwendung manchmal etwas umständlich sein kann. Ich benutze Magit , einen Emacs-Modus, der für die Arbeit mit Git sehr hilfreich ist. In Magit können Sie ausführen magit-status, die Unterschiede für die Änderungen finden, die Sie zurücksetzen möchten, die Zeilen auswählen, die Sie zurücksetzen möchten (oder einfach den Cursor auf Hunks setzen, die Sie zurücksetzen möchten, wenn Sie stattdessen jeweils einen Hunk zurücksetzen möchten jeweils eine Zeile) und drücken Sie k, um diese bestimmten Zeilen zurückzusetzen. Ich kann Magit nur empfehlen, wenn Sie Emacs verwenden.

Brian Campbell
quelle
Ich denke, dies ist ungefähr so ​​komplex wie die Lösung, die ich ursprünglich entwickelt habe, aber ich denke, meine ursprüngliche Lösung hat den Vorteil, dass die entfernten Leitungen 30 Tage lang gespeichert werden, weil sie festgeschrieben sind. Ich denke, vielleicht wäre es schön, ein Shell-Skript darum herum schreiben zu lassen.
Asmeurer
1
Entschuldigung, ich habe gerade festgestellt, dass es git checkoutauch eine -pFlagge gibt, die genau das tut, wonach Sie in einem einzigen Befehl gefragt haben. Entschuldigung für die vorherigen komplexen Schritte; Sie können nur verwenden git checkout -p. Was das Speichern von Dingen angeht, bevor ich etwas potenziell Zerstörerisches mache, mache ich oft einen git stash; git stash apply(oder erstelle einen Alias, der das als git checkpointoder so macht), um den aktuellen Baum in einem Stash aufzuzeichnen, damit ich darauf zurückgreifen kann, wenn etwas schief geht.
Brian Campbell
Los geht's, das ist die Lösung! Was den Alias ​​angeht, denke ich, dass so etwas git commit -a -m "Backup Commit" --edit; git reset HEAD^ besser wäre, weil es dann meinen Versteckzustand, den ich möglicherweise für etwas anderes verwende, nicht verschmutzen würde. Solange Sie den SHA1 haben, können Sie ihn innerhalb der nächsten 30 Tage pflücken. Mit --edit können Sie der Festschreibungsnachricht Informationen hinzufügen, um die SHA1 später zu finden, wenn Sie dies wünschen. Auf der anderen Seite würde dies das Git-Reflog verschmutzen, also denke ich, dass es ein Kompromiss ist, der auf dem basiert, was Sie tun.
Asmeurer
Der Checkpoint-Alias ​​funktioniert bei mir nicht: Es wird nur der erste Befehl ausgeführt, nicht der zweite. Das ist traurig, denn es hätte mir gefallen. Ich benutze Git Version 1.7.10.4.
Fabien
Gibt es eine Möglichkeit, git checkout -pdie Patches nicht auf den Index anzuwenden, sondern nur zu inszenieren?
Geremia
27
git diff > patchfile

Bearbeiten Sie dann die Patchdatei und entfernen Sie die Teile, die Sie nicht rückgängig machen möchten. Dann:

patch -R < patchfile
oktoberblu3
quelle
6
Diese Antwort ist jedoch besonders bewundernswert in ihrer Einfachheit und Benutzerfreundlichkeit. +1
tholy
Das generierte patchfilesieht in vim großartig aus und es hilft wirklich!
Bily
Perfekt. Kann bestätigen, dass es auch unter Windows mit Cygwin und Ubuntu Bash für Windows funktioniert.
Checo R
1
Beachten Sie, dass Sie auch git apply -Ranstelle von patch(nur um im Bereich von Git zu bleiben, oder in dem anderen Fall, der patchnicht verfügbar ist)
user1556435
patch: **** malformed patch at line 41: @@ -428,9 +443,9 @@ you should place your code here."
HappyFace
5

Du könntest es tun

git checkout master -- path/to/file

Für jede Datei, die Sie zurücksetzen möchten.

Drew Hoskins
quelle
Oder verwenden Sie HEAD anstelle von Master, wenn Sie an einem Zweig arbeiten. Wie es im Bericht "Git Status" heißt (zumindest in neueren Versionen).
Jonathan Leffler
1

Wie wäre es mit

  1. Sichern Sie die betroffenen Dateien mit Änderungen aus dem Index
  2. Verwenden git add -pSie diese Option, um nur die gewünschten Änderungen zum Index hinzuzufügen.
Abizern
quelle
1

Wenn ich 'git status' starte, heißt es:

$ git status
# On branch fr/fr.002
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#   modified:   makefile
#
no changes added to commit (use "git add" and/or "git commit -a")
$

Um die nicht bereitgestellten Änderungen abzubrechen, muss ich Folgendes ausführen:

git checkout -- makefile
Jonathan Leffler
quelle
3
Ich glaube, er hat sich gefragt, wie man einzelne Hunks zurücksetzt, nicht eine ganze Datei gleichzeitig. Dies ist natürlich die Lösung, wenn Sie nur alle Änderungen in einer Datei rückgängig machen müssen.
Brian Campbell
Ja - ich vermute du hast recht. Die Optionen 'git checkout -p' und 'git add -p' scheinen genau das zu sein, was gewünscht wird - wie Sie sagten.
Jonathan Leffler
1

Die Antwort von Brian Campbell stürzt mein Git, Version 1.9.2.msysgit.0, aus unbekannten Gründen ab. Mein Ansatz ist es also, Hunks, die ich behalten möchte, zu inszenieren, Änderungen in der Arbeitskopie zu verwerfen und dann die Bühne zu verlassen.

$ git add -p
   ... select the hunks to keep
$ git checkout -- .
$ git reset HEAD .
G-Wiz
quelle
1
Es gibt auch git stash -p. Du könntest es tun git stash -p; git reset --hard; git stash pop. Dies ist praktisch dasselbe wie das, was Sie tun, außer dass Sie keine Festschreibungsnachricht schreiben müssen.
Asmeurer
@asmeurer Prost. Meins erfordert keine Commit-Nachricht, aber es ist wahrscheinlich sinnvoller, den Stash als den Index dafür zu verwenden.
G-Wiz
0

Sie können die git checkoutNamen der Teile, die Sie rückgängig machen möchten, benennen.

Andrew
quelle