50 votes

Annuler la modification dans git (pas de réécriture de l'histoire)

J'ai fait une modification dans le script et l'a commis. Puis j'ai fait un peu d'autres changements, et les ont poussés à un dépôt distant et ces.

Puis j'ai réalisé que le premier changement que j'ai parlé, c'était stupide, et souhaitez l'annuler.. puis-je "annuler" qui s'engagent, sans manuellement copier/coller de la diff?

Un exemple: j'ai deux fichiers, a.py et 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

Puis-je annuler cette fonction de suppression, et de le faire apparaître comme "valider 4" (plutôt que de les supprimer commettre 1)

69voto

Jesse Rusak Points 33702

Oui, vous pouvez utiliser git revert pour cela. Voir le git section du manuel sur ce pour plus d'informations.

L'essentiel est que vous pouvez dire:

git revert 4f4k2a

Où 4f4k2a est l'id de la validation que vous souhaitez annuler, et il va essayer de le défaire.

36voto

VonC Points 414372

Juste un commentaire:

git revert aCommit

ne revenir le tout commit (comme dans "tous les fichiers de la partie de la livraison" ):
il calcule l'inverse de patch, l'applique sur la TÊTE et de s'engager.

Donc deux problèmes ici (le premier est facilement résolu):

  • il n'a toujours s'engager, de sorte que vous voudrez peut-être ajouter -no-commit option: "git revert --no-commit aCommit": c'est utile quand le retour de plus d'un s'engage' effet de votre index dans une rangée.
  • elle ne s'applique pas pour un fichier spécifique (que faire si vous avez un.py a fait partie d'un commit avec 1000 autres changements que vous pourriez ne pas vouloir revenir) ?
    Pour cela, si vous souhaitez extraire les fichiers spécifiques qu'ils étaient dans un autre commit, vous devriez voir git-checkout, plus précisément de l' git checkout <commit> <filename> de la syntaxe (qui n'est pas exactement ce qu'il vous faut dans ce cas)

Facile Git (Élie Newren) ont essayé d'apporter un plus "complète revenir" à la Git liste de Diffusion, mais sans beaucoup de succès:

Gens de temps en temps à vouloir "rétablir les modifications".

Maintenant, cela peut être:

  • les changements entre 32 et 29 révisions il y a,
  • il peut être toutes les modifications apportées depuis le dernier commit,
  • il pourrait être les changements depuis 3 s'engage il y a, ou
  • il pourrait être juste un commit.
  • L' utilisateur peut vouloir sous-ensemble de ces réversions juste des fichiers spécifiques,

(eg revert est documentée ici, mais je ne suis pas sûr qu'il fait partie de la distribution actuelle des par exemple si)

mais tout cela se résume à "revenir changements" à la fin.

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]

Ces types sont de "rétablissement de données" vraiment si différents qu'il doit être de différentes commandes, ou que certaines de ces opérations ne devraient pas être pris en charge par la simple commande revert?
Bien sûr, la plupart des utilisateurs, la plupart du temps ne sera probablement utiliser le "eg revert FILE1 FILE2..." la forme, mais je ne vois pas le mal à soutenir les capacités supplémentaires.

Aussi...est-il quelque chose de fondamental qui permettrait de garder le noyau git à partir de l'adoption d'un tel comportement?

Élie

Remarque: s'engage, par défaut, ne faites pas de sens pour la généralisation de l' revert de commande, et "git revert REVISION" aurait erreur avec les instructions (en indiquant à l'utilisateur d'ajouter l'option --en drapeau).


Disons que vous avez, de 50 engagés, 20 fichiers vous vous rendez compte que l'ancien commit X introduit des changements qui ne devrait pas avoir eu lieu.
Un peu de plomberie est dans l'ordre.
Ce que vous avez besoin est un moyen de la liste de tous les fichiers que vous devez revenir
(comme dans "pour annuler les modifications apportées à commettre X tout en gardant tous les changements ultérieurs"),
et puis, pour chacun d'eux:

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

La question ici est de compenser la perte de fonction sans effacer tous les changements ultérieurs dans un.py, vous voudrez peut-être garder.
Cette technique est parfois appelée "négatif fusion".

Depuis git merge-file <current-file> <base-file> <other-file> moyen:
intègre tous les changements qui mènent à partir de la <base-file> de <other-file> en <current-file>, vous pouvez restaurer supprimés fonction en disant que vous souhaitez intégrer tous les changements.)

  • de: X (où la fonction a été supprimée)
  • pour: X^ (la précédente livraison avant le X, où la fonction était toujours là)

Remarque: le '-p' argument qui vous permet de vérifier d'abord les changements sans rien faire sur le fichier en cours. Lorsque vous êtes sûr, supprimer cette option.

Remarque: l' git merge-file est pas aussi simple que cela: vous ne pouvez pas référencer les versions précédentes du fichier, juste comme ça.
(vous n'avez plus de et plus de la frustration du message: error: Could not stat X)
Vous devez:

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!

Si ce n'est à faire pour un grand nombre de fichiers dans une précédente livraison... quelques scripts est dans l'ordre ;)

4voto

Paul Points 12977

Pour annuler les modifications apportées à un seul fichier à l'intérieur d'un commit, comme VonC souligné, je voudrais checkout de la branche (master ou du tronc ou autre) et ensuite, checkout la version du fichier que je voulais revenir et de le traiter comme un nouveau commit:

$ 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'

Il y a probablement une de plomberie commande qui permette de le faire directement, mais je ne voudrais pas l'utiliser si je le savais. Ce n'est pas que je n'ai pas confiance Git, mais je n'ai pas confiance moi-même je n'aurais pas confiance, je savais, sans regarder ce qui a changé dans le fichier en question qui s'engagent et depuis. Et une fois que je regarde, c'est plus facile de construire un nouveau commit par l'édition de l' diff. Peut-être qu'après de modes de travail.

1voto

Mohan Nayaka Points 31

Jetez un oeil à cette git revert question. Il semble y avoir un problème de revenir plus âgés s'engage pas dans une consécutifs de la séquence, y compris la plus récente de la commettre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X