Comment «annuler» un commit Git annulé?

487

Étant donné un changement qui a été commitvalidé à l'aide revert, puis annulé à l' aide , quelle est la meilleure façon d'annuler cette annulation?

Idéalement, cela devrait être fait avec un nouveau commit, afin de ne pas réécrire l'historique.

JimmidyJoo
la source
4
Duplication possible de Comment puis-je corriger un commit git annulé?
phuclv
@phuclv un commentaire pour un éventuel doublon, pointe ici. L'un doit être marqué comme original et l'autre doit être marqué comme doublon
John Demetriou
@JohnDemetriou aucune question qui a un meilleur ensemble de réponses ne doit rester ouverte. Le temps n'est pas pertinent ici Comment traiter les questions en double?
phuclv
Je n'ai pas dit à propos du temps. Je viens de commenter l'un des deux sur la question
John Demetriou

Réponses:

385

Si vous n'avez pas encore poussé ce changement, git reset --hard HEAD^

Sinon, annuler le retour est parfaitement correct.

Une autre façon consiste à git checkout HEAD^^ -- .et ensuite git add -A && git commit.

Adam Dymitruk
la source
8
Notez que si vous souhaitez annuler la restauration sans appliquer immédiatement les modifications d'origine à la branche principale, vous pouvez (1) restaurer la branche d'origine si elle est supprimée, (2) cliquer sur "rétablir" sur la branche de restauration comme indiqué par Adam, puis ( 3) cliquez sur "modifier" dans l'en-tête du PR résultant et remplacez la branche cible par la branche d'origine au lieu de maître. Maintenant, votre branche d'origine peut être fusionnée pour effectuer les modifications précédemment annulées.
pauljm
1
Veuillez noter que cela supprimera toutes les modifications dans l'arborescence de travail et l'index. Utilisez git stash pour enregistrer les modifications que vous ne voulez pas perdre.
zpon
3
Quel est l'avantage de la méthode checkout && commit? Il semble que, dans le cas général git cherry-pickou alternativement, ce git revertsoient les moyens les plus simples de revenir sur un retour.
Robert Jack Will
5
Je pense qu'il serait utile de montrer comment:, Otherwise, reverting the revert is perfectly fine.puis aussi d'expliquer ce qui git checkout HEAD^^ -- .se passe.
Todd
3
Bon Dieu, n'utilisez pas git add -A... sauf si vous voulez ajouter chaque fichier au contrôle de version, ce qui n'est probablement pas ce que vous voulez.
Kaitain
474

git cherry-pick <original commit sha>
Fera une copie du commit d'origine, réappliquant essentiellement le commit

La restauration de la restauration fera la même chose, avec un message de validation plus compliqué:
git revert <commit sha of the revert>

L'une ou l'autre de ces façons vous permettra de ne git pushpas écraser l'historique, car elle crée un nouveau commit après le retour.
Lorsque vous tapez le commit sha, vous n'avez généralement besoin que des 5 ou 6 premiers caractères:
git cherry-pick 6bfabc

Stephan
la source
61
Il s'agit de la solution la plus élégante et la plus complète à la question des PO. Beaucoup mieux que la réponse acceptée avec ses hypothèses sur le retour de la validation à la tête de l'arbre de validation. L'op a également spécifiquement demandé une solution qui ne réécrit pas l'historique, de sorte que la solution difficile proposée dans la réponse acceptée est tout simplement fausse.
Timo
6
@Timo Pour clarifier, la réponse acceptée contient la solution que j'ai utilisée ("rétablir le retour") et a été publiée quelques heures après ma question, soit 3 ans plus tôt que cette réponse. Par conséquent, la coche.
JimmidyJoo
6
@JimmidyJoo Je sais que j'avais 3 ans de retard, je voulais juste que les gens viennent ici d'une recherche Google pour voir une meilleure réponse
Stephan
2
@Stephan Yep, mais encore une fois, pour clarifier - c'est une meilleure réponse, mais pas celle que j'ai utilisée pour résoudre mon problème. Je commentais simplement pourquoi la coche est là où elle se trouve. Question à tous: la convention SO exige-t-elle que je «maintienne» mes questions passées et que je réattribue des coches à mesure que de nouvelles réponses arrivent?
JimmidyJoo
3
@JimmidyJoo Je n'ai aucune idée de la convention SO. Mais en tant que chercheur Google, je préfère vraiment voir la meilleure réponse cochée. Et apprécierait les efforts de quiconque pour maintenir ses questions passées.
Paiman Roointan
30

Un commit de retour est comme n'importe quel autre commit dans git. Cela signifie que vous pouvez le rétablir, comme dans:

git revert 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746

Cela n'a de sens que de toute évidence une fois que les changements ont été poussés, et surtout quand vous ne pouvez pas forcer pousser sur la branche de destination ( ce qui est une bonne idée pour votre maître branche). Si le changement n'a pas été poussé, faites simplement le choix, annulez ou supprimez simplement la validation de retour selon les autres articles.

Dans notre équipe, nous avons une règle pour utiliser un retour sur les validations Revert qui ont été validées dans la branche principale, principalement pour garder l'historique propre, afin que vous puissiez voir quel commit rétablit quoi:

      7963f4b2a9d   Revert "Revert "OD-9033 parallel reporting configuration"
      "This reverts commit a0e5e86d3b66cf206ae98a9c989f649eeba7965f.
                    ...
     a0e5e86d3b6    Revert "OD-9055 paralel reporting configuration"
     This reverts commit 648d7d808bc1bca6dbf72d93bf3da7c65a9bd746.
                ...
     Merge pull request parallel_reporting_dbs to master* commit 
    '648d7d808bc1bca6dbf72d93bf3da7c65a9bd746'

De cette façon, vous pouvez retracer l'histoire et comprendre toute l'histoire, et même ceux qui ne connaissent pas l'héritage pourraient le découvrir par eux-mêmes. Alors que si vous choisissez ou rebasez des éléments, ces précieuses informations sont perdues (sauf si vous les incluez dans le commentaire).

De toute évidence, si un commit est revenu et est revenu plus d'une fois, cela devient assez compliqué.

Nestor Milyaev
la source
15

Inverser le retour fera l'affaire

Par exemple,

Si abcdefc'est votre commit et ghijklest le commit que vous avez lorsque vous avez annulé le commit abcdef, exécutez:

git revert ghijkl

Cela reviendra le retour

rafee_que_
la source
4

C'est stupide pour moi. Mais j'étais dans la même situation et je suis revenu pour des commits annulés. J'ai effectué des restaurations de numéros, j'ai donc dû effectuer une restauration pour chaque «validation de restauration».

Maintenant, mon histoire de commits est un peu bizarre.

histoire bizarre

C'est un projet pour animaux de compagnie donc c'est OK. Mais pour un projet réel, je préférerais aller au dernier commit avant de rétablir restaurer tout le code retourné ensemble dans un commit et un commentaire plus raisonnable.

RredCat
la source
4
Vous pouvez être intéressé par les réponses à une autre de mes questions: stackoverflow.com/questions/10415565/…
JimmidyJoo
2
Vous pouvez éviter la validation automatique et choisir votre message de validation à l'aide de l'indicateur --no-commit lors de la restauration, puis valider avec le message correspondant
David Barda
Vous pouvez également spécifier plusieurs ID de validation lors de l'utilisation de git revert (ils doivent être dans le bon ordre, je pense).
Aalex Gabi
Puis-je le faire depuis le bureau github?
Guillaume F.
4

Voici comment je l'ai fait:
si la branche a my_branchnameété incluse dans une fusion qui a été annulée. Et je voulais annuler my_branchname:

Je fais d'abord un git checkout -b my_new_branchnamede my_branchname.
Ensuite, je fais un git reset --soft $COMMIT_HASH$COMMIT_HASHest le hachage de validation du commit juste avant le premier commit de my_branchname(voir git log)
Ensuite, je fais un nouveau commit git commit -m "Add back reverted changes"
Puis je pousse la nouvelle branche git push origin new_branchname
Puis j'ai fait une pull request pour la nouvelle branche.

Drew LeSueur
la source
Chemin à parcourir quand il y a trop de "choix de cerise" à faire. Je ne comprends pas pourquoi cette réponse a si peu de votes positifs
Fundhor
2

Ou vous pouvez git checkout -b <new-branch>et git cherry-pick <commit>avant le pour et git rebaseabandonner le revertcommit. envoyer une demande de tirage comme précédemment

Ryan Chou
la source
1

Si vous n'aimez pas l'idée de "annuler une annulation" (en particulier lorsque cela signifie perdre des informations d'historique pour de nombreuses validations), vous pouvez toujours consulter la documentation de git sur "Annulation d'une fusion défectueuse" .

Étant donné la situation de départ suivante

 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E   <-- fixed-up topic branch

(W est votre retour initial de la fusion M; D et E sont des correctifs pour votre branche / commit de fonctionnalité initialement cassée)

Vous pouvez maintenant simplement rejouer les commits A à E, de sorte qu'aucun d'entre eux "n'appartienne" à la fusion annulée:

$ git checkout E
$ git rebase --no-ff P

La nouvelle copie de votre branche peut maintenant être fusionnée à masternouveau:

   A'---B'---C'------------D'---E'  <-- recreated topic branch
  /
 P---o---o---M---x---x---W---x
  \         /
   A---B---C----------------D---E
NobodysNightmare
la source
Bonne idée et merci pour le lien doc. Nous rebase généralement avec master avant de fusionner, mais git semble alors reconnaître que A ', B', C 'sont les mêmes que ceux d'avant, et j'ai maintenant D, E après W ( pastebin ). Des suggestions sur la façon de résoudre ce problème?
Kristoffer Bakkejord
0

Pour récupérer les modifications non et échelonnées qui ont été annulées après une validation:

git reset HEAD@{1}

Pour récupérer toutes les suppressions non organisées:

git ls-files -d | xargs git checkout --
Richa Goyal
la source