Annuler une fusion par pull request?

159

Quelqu'un a accepté une pull request qu'il ne devrait pas avoir. Maintenant, nous avons un tas de code cassé fusionné. Comment annuler une pull request? J'allais simplement annuler les modifications apportées au commit juste avant la fusion, mais j'ai remarqué qu'il fusionnait dans un tas de commits. Alors maintenant, il y a tous ces engagements de cette personne des jours avant la fusion. Comment pouvez-vous annuler cela?

Volonté
la source
7
Malgré l'avis de la réponse acceptée, VEUILLEZ ne pas forcer le push vers un référentiel si le dépôt est partagé avec quelqu'un d'autre. Vous courez le risque de ruiner le travail effectué par d'autres, et GitHub peut continuer à afficher cette pull request comme ayant été fusionnée. Une autre réponse à cette question explique un moyen plus sûr d'annuler une pull request.
alxndr
2
Remarque: au moins maintenant (juin 2014), GitHub propose le bouton "Revert" dans leur interface graphique Web Pull Request. Voir ma réponse ci
VonC
1
Le problème avec le bouton "Revert" est qu'il crée un nouveau commit comme inverse de la pull request, ce qui signifie que si vous voulez finalement fusionner ces modifications, l'utilisation du bouton "Revert" peut rendre cela beaucoup plus difficile.
FluffySamurai

Réponses:

159

Il y a une meilleure réponse à ce problème, même si je pourrais simplement le décomposer étape par étape.

Vous devrez récupérer et vérifier les dernières modifications en amont comme ceci, par exemple:

git fetch upstream
git checkout upstream/master -b revert/john/foo_and_bar

En jetant un œil au journal de validation, vous devriez trouver quelque chose de similaire à ceci:

commit b76a5f1f5d3b323679e466a1a1d5f93c8828b269
Merge: 9271e6e a507888
Author: Tim Tom <[email protected]>
Date:   Mon Apr 29 06:12:38 2013 -0700

    Merge pull request #123 from john/foo_and_bar

    Add foo and bar

commit a507888e9fcc9e08b658c0b25414d1aeb1eef45e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 12:13:29 2013 +0000

    Add bar

commit 470ee0f407198057d5cb1d6427bb8371eab6157e
Author: John Doe <[email protected]>
Date:   Mon Apr 29 10:29:10 2013 +0000

    Add foo

Vous souhaitez maintenant annuler l'intégralité de la demande d'extraction avec la possibilité de l'annuler plus tard. Pour ce faire, vous devrez prendre l'ID du commit de fusion .

Dans l'exemple ci-dessus, le commit de fusion est celui du haut où il est dit "Merged pull request # 123 ..." .

Faites ceci pour annuler les deux modifications ( "Ajouter une barre" et "Ajouter foo" ) et vous vous retrouverez avec dans un seul commit annulant l'intégralité de la pull request que vous pourrez annuler plus tard et garder l'historique des modifications propre:

git revert -m 1 b76a5f1f5d3b323679e466a1a1d5f93c8828b269
errordeveloper
la source
6
Cela devrait être la bonne réponse. Il y a une référence dans la page de manuel git-revert pour plus de détails sur la liste de diffusion git ici kernel.org/pub/software/scm/git/docs/howto/…
Justin Hamade
2
Pourquoi le git checkout upstream/master -b revert/john/foo_and_bar? que fait-il exactement?
Magne
4
@Magne - vous créez une nouvelle branche pour effectuer la restauration, dans laquelle vous pouvez ensuite choisir où fusionner la réversion. Fondamentalement, cela vous donne simplement plus de contrôle sur ce qu'il faut faire avec la branche. Dans mon cas, j'ai soumis une nouvelle pull request de cette branche "fixe" contenant la réversion vers notre branche develop, ce qui signifie que ma nouvelle pull request pourrait également être annulée si nécessaire. Cela a été fait pour une version où nous avons décidé de retirer le premier brouillon d'une fonctionnalité qui a été replanifiée. Pas de mauvais code, juste pas dans cette version.
Daniel Nalbach
3
J'ai appris une dure leçon sur celui-ci. Nous avons poussé une fonctionnalité dans notre branche de développement, mais nous avons réalisé qu'il y avait des problèmes de données et sommes revenus directement au développement. Plus tard, lorsque les choses ont été corrigées, nous voulions ajouter de nouvelles fonctionnalités de développement à cette branche pour tester leur compatibilité avec cette fonctionnalité avant de pousser, j'ai donc fusionné développer à la branche de fonctionnalités. Cela a également appliqué la validation de réversion, qui annulait chaque modification apportée à la branche de fonctionnalité. > <
Greg
86

Regardez votre graphe de commit (avec gitk ou un programme similaire). Vous verrez des validations de la demande d'extraction, et vous verrez vos propres validations et une validation de fusion (s'il ne s'agissait pas d'une fusion à avance rapide). Il vous suffit de trouver le dernier de vos propres commits avant la fusion et de réinitialiser la branche sur ce commit.

(Si vous avez le reflog de la branche, il devrait être encore plus facile de trouver le commit avant la fusion.)


(Modifier après plus d'informations dans les commentaires :)

D'accord, regardons le graphique:

capture d'écran 1

Je suppose que le dernier commit (le plus à droite) était votre mauvaise fusion par pull request , qui a fusionné la ligne bleue vue ici. Votre dernier bon commit serait celui avant sur la ligne noire, ici marqué en rouge:

entrez la description de l'image ici

Réinitialisez ce commit, et tout devrait bien se passer.

Cela signifie que, dans votre copie de travail locale, faites ceci (après vous être assuré que vous n'avez plus de choses non validées, par exemple par git stash):

git checkout master
git reset --hard 7a62674ba3df0853c63539175197a16122a739ef
gitk 

Maintenant, confirmez que vous êtes vraiment sur le commit que j'ai marqué là-bas, et vous ne verrez aucun des éléments tirés dans son ascendance.

git push -f origin master

(si votre télécommande github est nommée origin- sinon changez le nom).

Maintenant, tout devrait également avoir l'air correct sur github. Les commits seront toujours dans votre référentiel, mais ne seront accessibles par aucune branche, donc ne devraient pas y faire de mal. (Et ils seront toujours sur le référentiel de RogerPaladin, bien sûr.)

(Il peut y avoir un moyen spécifique à Github de faire la même chose sur le Web, mais je ne suis pas trop familier avec Github et son système de gestion des demandes d'extraction.)

Notez que si quelqu'un d'autre a déjà retiré votre master avec le mauvais commit, il a alors le même problème que vous avez actuellement et ne peut pas vraiment contribuer. avant de réinitialiser votre nouvelle version principale.

S'il est probable que cela se soit produit, ou si vous souhaitez simplement éviter tout problème, utilisez la git revertcommande à la place de git reset, pour annuler les modifications avec un nouveau commit, au lieu de revenir à un ancien. (Certaines personnes pensent que vous ne devriez jamais effectuer de réinitialisation avec les branches publiées.) Consultez les autres réponses à cette question pour savoir comment procéder.

Pour le futur:

Si vous ne voulez que certains des commits de la branche de RogerPaladin, envisagez d'utiliser à la cherry-pickplace de merge. Ou communiquez avec RogerPaladin pour les déplacer vers une succursale distincte et envoyer une nouvelle demande d'extraction.

Paŭlo Ebermann
la source
Mais nous avons une tonne de commits entre la fusion et son premier commit. Donc, comme nous avons le commit de fusion, nos propres commits, puis un autre commit par lui. On dirait que cela a fusionné avec de très vieux commits.
Volonté le
Oui, il fusionnera dans tout ce qui est un ancêtre du commit fusionné (et pas déjà un ancêtre de votre commit). Cela ne devrait pas vous empêcher de réinitialiser - les commits ne seront pas réorganisés par eux-mêmes, si vous n'avez pas effectué de rebase par la suite.
Paŭlo Ebermann le
1
Ouais, maintenant ça a l'air bien (mis à part l'étrange fusion en lui - même - mais cela pourrait être un problème dans le logiciel de graphe de réseau). :-) Je suis heureux d'avoir pu aider.
Paŭlo Ebermann
6
Je pense que cela peut être problématique si quelqu'un a retiré les mauvais commits et qu'ils envoient plus tard une pull request contenant les mêmes mauvais commits, ils se faufilent donc dans le repo. Ne serait-il pas plus sûr de créer un nouveau commit qui annule les mauvais commits? De cette façon, si les mauvais commits ont été tirés vers d'autres branches / fourches, ils seront effectivement supprimés par une autre traction vers cette autre branche / fourche? Je ne dis pas cela comme un fait, c'est ce que je pense peut être vrai, étant dans la même position que l'OP et ayant passé environ une heure à réfléchir à mes options.
Myles McDonnell
4
@Will je suggérerais de ne pas accepter cette réponse. Cela est bien pour le code qui n'a pas été poussé encore (dans ce cas, c'est une question SO plus pertinente, mais pour le code qui est partagé publiquement, en faisant une commande git qui réécrit l' histoire (dans ce cas, et une poussée de force est très mauvaise pratique). La réponse de @errordeveloper ci-dessous montre un moyen de le faire sans aucune réécriture de l'historique ni aucune pression forcée.reset --hard
asmeurer
34

Si l'attraction était la dernière chose qu'il a faite alors

git reset --hard HEAD~1
samthebest
la source
3
soyez prudent en suivant cette instruction, cela m'a fait reculer de 2 étapes, pas une.
szeitlin
1
@szeitlin Comment a-t-il pu vous faire reculer de 2 pas, pas un? Je sais que ce commentaire a été laissé il y a plus de 4 ans, mais je suis curieux de savoir si quelqu'un sait comment cela pourrait arriver. C'est très important pour moi. Merci.
Haradzieniec
Je ne me souviens pas maintenant, mais je suppose que cela pourrait arriver si j'avais fait un nouveau commit lorsque j'essayais de réinitialiser? Je voudrais juste le tester avec un repo factice si cela vous inquiète.
szeitlin
Celui-ci a bien fonctionné pour moi. Il a supprimé la demande d'extraction récemment fusionnée. Après git reset --hard HEAD~1, j'avais l'habitude git push origin -fde mettre à jour le référentiel distant. Mais soyez prudent, soyez prudent avant de faire cela.
Denis Oluka
24

À partir du 24 juin 2014, vous pouvez essayer d'annuler facilement un PR (voir « Annuler une demande de tirage ») avec:

Présentation du bouton Revert

vous pouvez facilement annuler une pull request sur GitHub en cliquant sur Revert:

https://camo.githubusercontent.com/0d3350caf2bb1cba53123ffeafc00ca702b1b164/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6c696e6b2e706e67

Vous serez invité à créer une nouvelle demande d'extraction avec les modifications annulées:

https://camo.githubusercontent.com/973efae3cc2764fc1353885a6a45b9a518d9b78b/68747470733a2f2f6769746875622d696d616765732e73332e616d617a6f6e6177732e636f6d2f68656c702f70756c6c5f72657175657374732f7265766572742d70756c6c2d726571756573742d6e65772d70722e706e67

Il reste à tester si ce retour utilise -mou non (pour le retour des fusions également)

Mais Adil H Raza ajoute dans les commentaires (décembre 2019):

C'est le comportement attendu, il a créé une nouvelle branche et vous pouvez créer un PR de cette nouvelle branche vers votre master.
De cette façon, à l'avenir, vous pouvez annuler le retour si nécessaire, c'est l'option la plus sûre et ne change pas directement votre fichier master.


Attention : Korayem souligne dans les commentaires que:

Après un retour, disons que vous avez apporté d'autres modifications sur la branche Git et créé un nouveau PR à partir de la même branche source / destination.
Vous trouverez le PR ne montrant que les nouveaux changements, mais rien de ce qui était là avant de revenir .

Korayem nous renvoie à " Github: Modifications ignorées après revert ( git cherry-pick, git rebase) " pour en savoir plus.

VonC
la source
J'ai essayé cela et cela a créé une nouvelle branche au lieu d'annuler PR sur le maître?
Грозный
Étrange. Pourriez-vous poser une nouvelle question pour illustrer ce comportement?
VonC
c'est le comportement attendu, il a créé une nouvelle branche et vous pouvez créer un PR de cette nouvelle branche à votre maître. De cette façon, à l'avenir, vous pouvez annuler le retour si nécessaire, c'est l'option la plus sûre et ne change pas directement votre maître.
Adil H.Raza
1
@ AdilH.Raza Merci. J'ai inclus votre commentaire dans la réponse pour plus de visibilité.
VonC
1
@VonC croise les doigts, cela sauvera les développeurs du monde entier de trop d'agonie et de perte de temps
Korayem
8

Pour annuler une demande d'extraction github avec des validations que vous ne souhaitez pas supprimer, vous devez exécuter un:

git reset --hard --merge <commit hash>

le hachage de validation étant le commit AVANT de fusionner la demande d'extraction. Cela supprimera tous les validations de la demande d'extraction sans influencer les validations dans l'historique.

Un bon moyen de le trouver est d'aller à la demande d'extraction maintenant fermée et de trouver ce champ:

Pull Request Image Pull Request Image

Après avoir exécuté le git reset, exécutez un:

git push origin --force <branch name>

Cela devrait rétablir la branche avant la demande d'extraction SANS affecter les validations dans la branche parsemée dans l'historique des validations entre les validations de la demande d'extraction.

ÉDITER:

Si vous cliquez sur le bouton de retour sur la demande d'extraction, cela crée un commit supplémentaire sur la branche. Il N'EST PAS annulé ou annulé. Cela signifie que si vous appuyez sur le bouton de retour, vous ne pouvez pas ouvrir une nouvelle demande d'extraction pour rajouter tout ce code.

MoelleuxSamouraï
la source
Excellent moyen de régler les choses sans avoir besoin de revenir en
arrière
Merci! C'était ce que j'avais prévu de faire, mais cela aurait représenté environ 200 engagements à choisir.
FluffySamurai
1

J'utilise cet endroit tout le temps, merci.

Je cherchais comment annuler une pull request et je suis arrivé ici.

J'étais sur le point de juste git reset --hard"il y a longtemps" et de faire une avance rapide vers l'endroit où j'étais avant de faire la pull request.

En plus de regarder ici, j'ai également demandé à mon collègue ce qu'il ferait, et il avait généralement une bonne réponse: en utilisant l'exemple de sortie dans la première réponse ci-dessus:

git reset --hard 9271e6e

Comme pour la plupart des choses dans Git, si vous le faites d'une manière qui n'est pas facile, vous le faites probablement mal.

Mike Marshall
la source