Annuler le changement dans git (ne pas réécrire l’historique)

J’ai modifié un script et l’ai engagé. Ensuite, j’ai apporté quelques modifications et je les ai envoyées dans un référentiel distant.

Puis je me suis rendu compte que le premier changement que j’ai mentionné était stupide et que je voulais le défaire. Puis-je “annuler” la validation sans copier / coller manuellement le diff?

Par 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 docssortingng in a.py 

Puis-je annuler la suppression de cette fonction et la faire apparaître comme “commit 4” (plutôt que de supprimer commit 1)

Oui, vous pouvez utiliser git revert pour cela. Voir la section du manuel git à ce sujet 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 l’annuler.

Juste un commentaire:

 git revert aCommit 

ne retourne pas le tous les commit (comme dans ” tous les fichiers faisant partie du commit”):
il calcule un patch inverse, l’applique sur HEAD et commet.

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

  • il se commet toujours, vous pouvez donc append l’option -no-commit : ” git revert --no-commit aCommit “: c’est utile pour rétablir l’effet de plusieurs commits dans votre index.
  • il ne s’applique pas à un fichier spécifique (et si vous participiez à un commit avec 1000 autres modifications que vous ne souhaitez peut-être pas rétablir)?
    Pour cela, si vous souhaitez extraire des fichiers spécifiques tels qu’ils étaient dans une autre validation, vous devriez voir git-checkout , en particulier la syntaxe git checkout (ce n’est cependant pas exactement ce dont vous avez besoin dans ce cas).

Easy Git (Elijah Newren) a essayé d’apporter un retour plus complet à la liste Git Mailing ; mais sans grand succès:

Les gens veulent parfois “annuler les changements”.

Maintenant, cela peut être:

  • les changements entre 32 et 29 révisions il y a,
  • ce pourrait être tous les changements depuis le dernier commit,
  • ce pourrait être les changements depuis 3 commits il y a, ou
  • ce pourrait être juste un engagement spécifique.
  • L’ utilisateur peut vouloir sous-compléter de telles réversions pour des fichiers spécifiques ,

( eg revert est documenté ici , mais je ne suis pas sûr que cela fasse partie de la dissortingbution actuelle de, par exemple)

mais tout se résume à “renverser les 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 sortingal~7 bar.c baz. # Undo changes made in sortingal~7 to bar.[ch] 

Ces types de “réversion de données” sont-ils si différents qu’il devrait y avoir des commandes différentes, ou que certaines de ces opérations ne devraient pas être sockets en charge par la simple commande de restauration?
Bien sûr, la plupart du temps, la plupart des utilisateurs utiliseront probablement le eg revert FILE1 FILE2...eg revert FILE1 FILE2... “, mais je ne voyais pas de mal à supporter les fonctionnalités supplémentaires.

En outre, y a-t-il quelque chose de fondamental qui empêcherait le kernel d’adopter un tel comportement?

Elijah

Note: les commits par défaut n’ont pas de sens pour la commande d’ revert généralisée, et ” git revert REVISION ” provoquerait une erreur avec des instructions (indiquant à l’utilisateur d’append l’indicateur –in).


Disons que vous avez, sur 50 engagés, 20 fichiers dont vous vous rendez compte que l’ancien commit X a introduit des changements qui n’auraient pas dû avoir lieu.
Une petite plomberie est en ordre.
Ce dont vous avez besoin est un moyen de lister tous les fichiers spécifiques que vous devez restaurer
(comme dans “pour annuler les modifications apscopes dans commit X tout en conservant toutes les modifications ultérieures” ),
et ensuite pour chacun d’eux:

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

Le problème ici est de récupérer la fonction perdue sans effacer toutes les modifications ultérieures dans a.py que vous souhaitez conserver.
Cette technique est parfois appelée “fusion négative”.

Comme git merge-file signifie :
intègre toutes les modifications qui vont du à dans , vous pouvez restaurer la fonction supprimée en disant que vous souhaitez incorporer toutes les modifications.)

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

Note: l’argument -p qui vous permet d’examiner d’abord les modifications sans rien faire sur le fichier en cours. Lorsque vous êtes sûr, supprimez cette option.

Remarque : le git merge-file n’est pas si simple : vous ne pouvez pas référencer les versions précédentes du fichier comme ça.
(vous auriez encore et encore le message frustrant: 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 cela doit être fait pour un grand nombre de fichiers dans une validation précédente … certains scripts sont en ordre;)

Pour ramener les modifications à un seul fichier dans une validation, comme VonC l’a fait remarquer, j’examinerais la twig (master ou trunk ou autre), puis checkout la version du fichier que je voulais restaurer et la 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 commande de plomberie qui le ferait directement, mais je ne l’utiliserais pas si je le savais. Ce n’est pas que je ne fais pas confiance à Git, mais je ne me fais pas confiance – je ne crois pas que je savais sans regarder ce qui avait été changé dans ce fichier et depuis lors. Et une fois que je regarde, il est plus simple de créer un nouveau commit en éditant le diff . C’est peut-être juste un style de travail personnel.

Jetez un oeil à cette question retourne git . Il semble y avoir un problème de retour des anciens commits si ce n’est dans une séquence consécutive, y compris la validation la plus récente.