web-dev-qa-db-fra.com

Comment puis-je annuler une fusion dans Mercurial et ensuite revenir à cette branche?

J'ai deux branches, default et branch1. Par erreur, une personne de notre équipe a fusionné branche1 avec défaut. Le contenu de branche1 n'est pas encore prêt à fusionner avec le contenu par défaut (il contient une refonte majeure de l'environnement de génération et de déploiement).

Nous avons fait une expérience avec 'backgg', en annulant la fusion (je ne suis pas sûr que ce soit la bonne façon de le faire). Ensuite, les modifications de branch1 sont supprimées par défaut, ce qui est correct - mais nous ne pouvons pas ressusciter avec branch1. 

Comment devrions-nous résoudre ce problème?

51
Peter Moberg

Il existe de nombreux scénarios dans lesquels vous souhaiterez peut-être procéder. Je vais faire de chaque scénario un titre afin que vous puissiez trouver le scénario qui convient à votre cas. Notez que j'apprends toujours Mercurial, et j'aimerais des conseils si quelque chose que je dis est faux, en utilisant la mauvaise terminologie, pourrait être mieux fait, etc.

Pas d'autres modifications, fusion non partagée (pas de push/pull)

Le programmeur a fusionné, mais n'a rien fait d'autre ni partagé les modifications avec qui que ce soit, de quelque manière que ce soit

Dans ce cas, supprimez simplement le clone local et récupérez un nouveau clone dans un référentiel sécurisé.

Modifications locales en haut de la fusion, non partagées

Le programmeur a fusionné et a continué à travailler en fonction de cette fusion. Les changesets qui ont suivi la fusion doivent être conservés, mais la fusion elle-même doit être supprimée. Les modifications (fusion + modifications suivantes) n'ont été partagées avec personne 

Dans ce cas, je ferais l'une des quatre suivantes:

  1. Essayez d'utiliser l'extension REBASE, cela déplacera les changesets d'un emplacement à un autre. Si les ensembles de modifications sont basés sur des modifications de code introduites lors de la fusion, un travail manuel doit être effectué pour rapprocher les différences.
  2. Essayez d’utiliser l’extension MQ pour extraire les ensembles de modifications à conserver dans une file d’attente de correctifs, puis repoussez-les à un emplacement différent. Cela posera toutefois le même problème que l’extension REBASE en termes de modifications basées sur la fusion.
  3. Essayez d'utiliser l'extension TRANSPLANT pour "copier" les modifications d'un emplacement à un autre. Néanmoins, le même problème existe que pour les deux premiers.
  4. Refaites le travail, probablement à l'aide d'un outil de différenciation pour prendre en compte les modifications apportées aux ensembles de modifications que je souhaite supprimer, puis recommencez-les à l'emplacement correct.

Pour supprimer le jeu de modifications de fusion + tous les jeux de modifications suivants, il existe plusieurs options:

  1. Utilisez la commande strip dans l'extension MQ

    hg strip <hash of merge changeset>
    
  2. Clonez et extrayez, et spécifiez le hachage des changesets menant à, mais sans inclure la fusion. Essentiellement, créez un nouveau clone en extrayant du clone endommagé vers un nouveau, et évitez d’intégrer la fusion que vous ne souhaitez pas.

    hg clone damaged -r <hash of first parent> .
    hg pull damaged -r <hash of second parent>
    

Fusionnez aux autres, contrôlez les clones

Le programmeur a poussé vers le référentiel maître, ou vers une autre personne, ou une personne extraite du référentiel de programmeurs. Cependant, vous (en tant que groupe de développeurs) avez le contrôle de tous les référentiels, vous pouvez contacter et parler à tout le monde avant que plus de travail ne soit fait

Dans ce cas, je verrais si les étapes 1 ou 2 pourraient être effectuées, mais cela peut être nécessaire dans de nombreux endroits, ce qui peut impliquer beaucoup de travail.

Si personne n'a effectué de travail basé sur le groupe de modifications de fusion, j'utiliserais les étapes 1 ou 2 pour nettoyer, puis passer au référentiel principal et demander à chacun d'obtenir un nouveau clone à partir du référentiel principal.

Fusionnez, vous n'avez pas le contrôle sur les clones

Le programmeur a poussé le mergeset, et vous ne savez pas qui aura le changeset de fusion. En d’autres termes, si vous réussissez à l’éradiquer de vos référentiels, un Push-Push errant de la part de quelqu'un qui l’a encore le ramènera.

Ignorez le changeset de fusion et travaillez dans les deux branches comme si de rien n'était. Cela laissera une tête pendante. Vous pouvez ensuite, lorsque vous aurez fusionné les deux branches, effectuer une fusion nulle pour que cette tête la supprime.

  M         <-- this is the one you want to disregard
 / \
*   *
|   |
*   *
|   |

Continuez simplement à travailler dans les deux branches:

|   |
*   *
| M |       <-- this is the one you want to disregard
|/ \|
*   *
|   |
*   *
|   |

Ensuite, vous fusionnez les deux, la fusion que vous souhaitez:

  m
 / \
*   *
|   |
*   *
| M |       <-- this is the one you want to disregard
|/ \|
*   *
|   |
*   *
|   |

Vous pouvez ensuite procéder à une fusion nulle pour vous débarrasser de la tête pendante. Malheureusement, je ne sais pas comment faire cela si ce n'est via TortoiseHg. Il y a une case à cocher où je peux ignorer les modifications de l'une des branches.

Avec TortoiseHg, je mettrais à jour la fusion que je veux conserver (le plus haut m, en minuscule), puis sélectionnez et cliquez avec le bouton droit de la souris sur la tête de fusion pendante ci-dessous, puis cochez la case "Annuler tous les changements de la révision cible : discard changes from target

Nous avons fait une expérience avec 'backgg', en annulant la fusion (je ne suis pas sûr que ce soit la bonne façon de le faire). Ensuite, les modifications de branch1 sont supprimées par défaut, ce qui est correct - mais nous ne pouvons pas ressusciter avec branch1.

J'utilise backout pour annuler la fusion. Vous ne pouvez pas rétablir la fusion, mais vous pouvez "annuler la fusion avec la sauvegarde en arrière", c’est-à-dire que lorsque vous souhaitez rétablir la fusion, vous effectuez une "sauvegarde en arrière-plan" sur "Sauvegarde du groupe de modifications de fusion ...", puis une nouvelle fusion.

Exemple:

  7     M       remerge
  6   /   \
  5   *   |     hg backout 3 (backout backout)
  4   |   *     fix error 
  3   *   |     hg backout 2
  2   M   |     fail merge
    /     \
  1 *     *
    |     |
4
Konstantin Vdovkin

Merci à tous pour votre participation! Comme nous étions en quelque sorte pressés de résoudre le problème et que notre groupe est relativement nouveau dans Mercurial, nous avons utilisé une solution très pragmatique.

Sur notre serveur de référentiel, nous avons créé un nouveau référentiel, puis nous avons cloné l'ancien référentiel jusqu'à la révision juste avant la fusion. Ensuite, poussez le nouveau clone sur le serveur et envoyez le nouveau lien à tout le monde. Heureusement, nous sommes une petite équipe de développement.

Ce n’est peut-être pas la façon la plus simple de résoudre le problème, mais cela a fonctionné :)

1
Peter Moberg

Cette réponse suppose que vous avez déjà poussé}

Cela donnerait (au moins une) tête non résolue, selon ce que vous venez d'oublier. Plus selon qui vient de pousser de quelle branche.

J'adore HG et l'utilise avidement, mais leur idée de branche peut conduire quelqu'un de vif quand elle est associée à une histoire intentionnellement (immuable).

En général, je clone une sauvegarde (locale) du référentiel avant de procéder à une fusion de branche, pour cette raison uniquement. Je vérifie toujours avant de tirer.

Eric Raymond travaille sur quelque chose qui est plus ou moins agnostique sur DVCS et qui peut (espérons-le) aider dans des situations similaires à celles que vous avez décrites, mais je ne pense pas que le soutien de HG sera pleinement mis en œuvre dans une semaine ou deux. Pourtant, il pourrait être intéressant de regarder. 

Mais utile seulement si personne n’a tiré la pointe "ooopsie".

0
Tim Post

Vous ne pouvez pas vraiment éviter une fusion bien. OMI, la meilleure façon de gérer cela serait tout simplement d’abandonner la fusion et de continuer la série de changesets d’avant la fusion, en laissant une tête pendante (qui peut être supprimée). Si d’autres changements sont intervenus depuis la fusion, ils peuvent être redistribués sur la nouvelle "bonne" tête.

0
Ringding

J'ai eu ce problème précis. Un collègue a accidentellement fusionné ma branche dans la branche par défaut alors qu'elle était encore incomplète. Au départ, je venais d’annuler cette fusion qui semblait bien fonctionner jusqu’à ce que je veuille fusionner ma branche par défaut pour la conservation. Les fichiers dont j'avais besoin étaient marqués pour suppression lors de la fusion.

La solution a été de remonter à mon retour d'origine, ce qui a corrigé l'erreur de mon collègue et de revenir en arrière. Cela empêchait les fichiers d'être marqués comme supprimés et me permettait de fusionner ma branche par défaut.

0
Justin