2009-03-13 4 views
44

Ich habe eine Änderung an einem Skript vorgenommen und es übernommen. Dann habe ich ein paar andere Änderungen vorgenommen und sie in ein Remote-Repository verschoben.Änderung in git rückgängig machen (Geschichte nicht umschreiben)

Dann erkannte ich, dass die erste Änderung, die ich erwähnte, dumm war, und will es rückgängig machen .. Kann ich das "commit", ohne manuell kopieren/einfügen die diff?

Als Beispiel: Ich habe zwei Dateien, a.py und b.py:

Commit 1: 
I delete a function in a.py 

Commit 2: 
I change a few lines in b.py 

Commit 3: 
I change the docstring in a.py 

Kann ich diese Funktion Löschung rückgängig zu machen, und es scheint, als „4 begehen“

(statt 1 verpflichten zu löschen)
+13

Oi, es ist "realisiert", nicht "realisiert"! (Ich bin nicht amerikanisch ..) – dbr

+3

Ihre Rechtschreibung wurde von einem Menschen korrigiert, die Yards und Füße verwenden, um Dinge zu messen ... ha ha – FaddishWorm

Antwort

57

Ja, Sie können hierfür git revert verwenden. Weitere Informationen finden Sie unter git manual section on this.

Der Kern ist, dass man sagen kann:

git revert 4f4k2a 

Wo 4f4k2a ist die ID des begehen Sie rückgängig machen möchten, und es wird versuchen, sie rückgängig zu machen.

+0

Aha, natürlich, danke! – dbr

+0

BTW! Es wird das Commit 1 Objekt löschen – aatifh

+0

Hm, es schien nicht zu löschen, die rückgängig gemacht Commit .. – dbr

31

Nur ein Kommentar:

git revert aCommit 

hat zufällt die alle begehen (wie in "alle Dateien Teil einer Übertragung"):
es berechnet einen Reverse-Patch, gilt es auf HEAD und begehen.

So zwei Probleme (die erste einfach zu lösen ist):

  • es nicht immer begehen, so dass Sie -no-commit Option hinzufügen möchten: „git revert --no-commit aCommit“: Das ist nützlich, wenn mehr zurückkehrt als man verpflichtet sich, den Index hintereinander zu beeinflussen.
  • es gilt nicht für eine bestimmte Datei (was ist, wenn Sie a.py Teil einer Festschreibung mit 1000 anderen Änderungen waren, die Sie nicht wiederherstellen möchten)?
    Dafür wenn Sie bestimmte Dateien extrahieren möchten, wie sie in einem anderen waren begehen, sollten Sie git-checkout, speziell die git checkout <commit> <filename> Syntax sehen (das ist nicht genau das, was Sie in diesem Fall müssen allerdings)

Easy Git (Elijah Newren) versucht, eine mehr "komplette Rückstellung" zum Git Mailing list zu bringen; aber ohne viel Erfolg:

Leute gelegentlich wollen "Änderungen rückgängig machen".Jetzt

, so kann dieser:

  • die Veränderungen zwischen 32 und 29 Änderungen vor,
  • es alle Änderungen sein könnte, da die letzten Commit,
  • es die Änderungen sein könnten, da 3 verpflichtet vor oder
  • es könnte nur ein bestimmtes Commit sein.
  • Der Benutzer solche Umkehrungen nur bestimmte Dateien,

(eg revert ist documented here, aber ich bin nicht sicher, es ist ein Teil der Stromverteilung von zB though)

der Teilmenge möchten

aber alles läuft darauf hinaus, "Änderungen rückgängig zu machen" am Ende.

eg revert --since HEAD~3 # Undo all changes since HEAD~3 
eg revert --in HEAD~8  # much like git revert HEAD~8, but nocommit by default 
eg revert --since HEAD foo.py # Undo changes to foo.py since last commit 
eg revert foo.py    # Same as above 
eg revert --in trial~7 bar.c baz. # Undo changes made in trial~7 to bar.[ch] 

Sind diese Arten von wirklich so anders „Daten zurückkehrt“, dass es verschiedene Befehle sein müssen, oder dass einige dieser Operationen sollten nicht durch den einfachen revert Befehl unterstützt werden?
Sicher, die meisten Benutzer werden die meiste Zeit wahrscheinlich das "eg revert FILE1 FILE2..." Formular verwenden, aber ich sah nicht den Schaden bei der Unterstützung der zusätzlichen Fähigkeiten.

Auch ... gibt es etwas Grundlegendes, das den Core-Git davon abhält, ein solches Verhalten anzunehmen?

Elijah

Hinweis: begeht standardmäßig keinen Sinn für den verallgemeinerten revert Befehl machen, und „git revert REVISION“ würde mit Anweisungen Fehler aus (erklären den Benutzer, die --in Flag hinzuzufügen).


Können sagen, Sie haben, von 50 begangen, 20 Dateien, die Sie erkennen, dass alte begehen X Änderungen eingeführt, die nicht stattgefunden haben soll.
Ein wenig Rohrleitungen ist in Ordnung.
Was Sie brauchen, ist ein Weg, um alle entsprechenden Dateien, die Sie müssen zur Liste zurückzukehren
(wie in „Änderungen zu stornieren in begehen X, während alle nachfolgenden Änderungen zu halten“),
und dann für jede sie aus:

git-merge-file -p a.py X X^ 

Das Problem hier ist die verlorene Funktion wiederherzustellen, ohne alle nachfolgenden Änderungen in a.py Verwischen Sie vielleicht zu halten.
Diese Technik wird manchmal als "negative Verschmelzung" bezeichnet.

Seit git merge-file <current-file> <base-file> <other-file>means:
alle Änderungen enthält, die von der <base-file>-<other-file> in <current-file> führen, können Sie wiederherstellen die gelöschte Funktion mit den Worten: Sie alle Änderungen zu übernehmen wollen)

    .
  • von: X (wo die Funktion gelöscht wurde)
  • an: X^(das vorherige Commit vor X, wo die Funktion noch da war)

Hinweis: das -p Argument, das Sie zuerst die Änderungen ohne etwas zu tun auf der aktuellen Datei überprüfen kann. Wenn Sie sicher sind, entfernen Sie diese Option.

Hinweis: die git merge-file ist not that simple: Sie keine früheren Versionen der Datei wie das gerade verweisen können.
(Sie müßten über und über die frustrierende Nachricht: error: Could not stat X)
Sie müssen:

git cat-file blob a.py > tmp/ori # current file before any modification 
git cat-file blob HEAD~2:a.py > tmp/X # file with the function deleted 
git cat-file blob HEAD~3:a.py > tmp/F # file with the function which was still there 

git merge-file a.py tmp/X tmp/F # basically a RCS-style merge 
           # note the inversed commit order: X as based, then F 
           # that is why is is a "negative merge" 
diff -u a.py tmp/ori # eyeball the merge result 
git add a.py 
git commit -m "function restored" # and any other changes made from X are preserved! 

Wenn dies für eine große Anzahl von Dateien in einem früheren begehen ... einige getan werden Scripting ist in Ordnung;)

+0

Ich glaube nicht, Sie brauchen den Bindestrich in: 'git checkout ' – Paul

5

um die Änderungen nur auf eine Datei in einem Commit zurückkehren, wie VonC wies darauf hin, würde ich checkout den Zweig (Master oder Stamm oder was auch immer) und dann checkout die Version der Datei, die ich wollte rückgängig machen und t reat als neue begehen:

$ git checkout trunk 
$ git checkout 4f4k2a^ a.py 
$ git add a.py 
$ git diff    #verify I'm only changing what I want; edit as needed 
$ git commit -m 'recover function deleted from a.py in 4f4k2a' 

Es gibt wohl ein Sanitär-Befehl ist, dass dies direkt tun würde, aber ich würde es nicht verwenden, wenn ich es wusste. Es ist nicht so, dass ich Git nicht traue, aber ich vertraue mir selbst nicht - ich würde nicht darauf vertrauen, dass ich wusste, ohne zu schauen, was in dieser Datei in diesem Commit geändert wurde und seitdem. Und wenn ich einmal nachdenke, ist es einfacher, ein neues Commit zu erstellen, indem Sie die diff editieren. Vielleicht ist das nur ein persönlicher Arbeitsstil.

+1

Zwei Kommentare: 1/Wenn die Funktion wurde im 4f4k2a commit für den a.py gelöscht, solltest du a.py nicht vom * vorherigen * commit auschecken? (Der eine * vor * 4f4k2a, wie in 4f4k2a ^?) 2/Würde das nicht komplett die aktuelle Version von a.py löschen? Was ist, wenn ich nachfolgende Änderungen beibehalten möchte? – VonC

+0

Ich würde lieber eine "negative Zusammenführung" mit git-merge-Datei machen: siehe meine fertige Antwort – VonC

+0

1) Ja. Danke für die Korrektur des anderen Tippfehlers. 2) Ja - deshalb müsste ich das diff sehen. Ich würde tatsächlich einen gehackten Diffmerge im 3-Wege-Merge-Modus verwenden, der mir einen nützlicheren Vergleich zeigt, mit dem ich vertraut bin, aber git diff ist brauchbar. Der Punkt ist: Ich bin nur zuversichtlich, wenn ich den Code angeschaut habe. – Paul

1

Werfen Sie einen Blick auf this git revert question. Es scheint ein Problem zu geben, das ältere Commits rückgängig macht, wenn nicht in einer fortlaufenden Sequenz einschließlich des letzten Commits.

+0

Upvoting, weil dies nützlich war, aber es sollte eher ein Kommentar als eine Antwort sein. – tripleee