La sauvegarde en arrière de fusion sur les Mercurial

Comment inverser l'effet d'une fusion sur polarisé branches sans mourir d'agonie?

ce problème me tourmente depuis mois et j'ai finalement abandonné.

vous avez 1 Dépôt, avec 2 nommé Branches. A et B.

les changements qui se produisent en A se produiront inévitablement en B.

les changements qui se produisent directement sur B ne doivent jamais se produire on A.

dans une telle configuration, la fusion de " B " en "A" produit un grave problème dans le dépôt, car tous les changements à B apparaissent en A comme s'ils avaient été faits en A.

la seule façon "normale" de se remettre de cette situation semble être de "revenir sur" la fusion, c'est-à-dire:

 hg up -r A 
 hg backout -r BadMergeRev --parent BadMergerevBeforeOnA 

qui semble tout beau et élégant, jusqu'à ce que vous décidiez de fusionner plus tard dans la bonne direction, et vous finissez avec toutes sortes de choses désagréables qui se produisent et le code qui a été effacé / commenté sur spécifiquement la branche B devient soudainement Non effacé ou non corrigé.

il n'y a pas eu de solution viable à ce problème jusqu'à présent si ce n'est de "laisser faire sa chose, puis régler à la main tous les problèmes" et que pour être honnête est un peu fubar.

Voici une image clarifiant le problème:

[image originale perdue]

dossiers C & E ( ou les changements C & E) doivent apparaître seulement sur la branche b, et non sur la branche A. La révision A9 ici (branche a, revno 9 ) est le début du problème.

révisions A10 et A11 sont les phases "backout merge" et "merge the backout".

et la révision B12 est impitoyable, laissant tomber à plusieurs reprises un changement qui était destiné à ne pas être abandonné.

ce dilemme a causé beaucoup de frustration et la fumée bleue et je voudrais mettre un terme à il.

Note

il peut être la réponse évidente d'essayer d'interdire la fusion inverse de se produire, soit avec des crochets ou avec des politiques, j'ai trouvé que la capacité de tout gâcher est assez élevé et la chance qu'il se produise si probable que même avec des contre-mesures, vous doit encore supposer que inévitablement, il va se produire afin que vous pouvez résoudre quand il se produit.

à Elaborer

dans le modèle, j'ai utilisé des fichiers séparés. Cela rend le problème simple. Ils représentent simplement changements arbitraires qui pourrait être une ligne séparée.

aussi, pour ajouter l'insulte à la blessure, il y a eu des changements substantiels sur la branche a qui laisse le problème debout "est-ce que les changements dans la branche A sont en conflit avec les changements dans la branche B qui vient de se présenter ( et a été retiré ) qui ressemble à un changement sur branche a au lieu de "

Sur L'Histoire De La Réécriture Des Astuces:

le problème avec toutes ces solutions rétro-actives est le suivant:

  1. nous avons 9000 commits.
  2. le clonage prend donc une demi-heure
  3. S'il existe , même une mauvais clone du dépôt quelque part , il y a un liklihood de revenir dans contact avec le dépôt original,et le frapper à nouveau.
  4. tout le monde a déjà cloné ce dépôt, et maintenant plusieurs jours se sont écoulés avec des commits en cours.
  5. un tel clone, se trouve être un site en direct, donc "essuyer celui-ci et à partir de zéro" = "big nono "

(Je l'admets, beaucoup de ce qui précède est un peu stupide, mais ils sont hors de mon contrôle ).

le seul les solutions qui sont viables sont celles qui supposent que les gens peuvent et vont faire tout mal, et qu'il y a un moyen de "défaire" cette injustice.

77
demandé sur Brant Bobby 2008-11-05 20:25:11

5 réponses

je pense que j'ai trouvé une solution qui fixe en permanence la mauvaise Fusion, et qui ne vous oblige pas à vérifier manuellement tout diffs. Le truc est de revenir en arrière dans l'histoire et de générer des propagations parallèles à la mauvaise Fusion.

donc nous avons un dépôt avec des branches séparées par version maintenue d'un seul produit. Comme la situation pose la question, toutes les modifications effectuées sur une branche d'une version antérieure (c'est à dire. les corrections de bug pour dans cette version) doit tous finalement être fusionné les branches des versions ultérieures.

donc spécifiquement, si quelque chose est enregistré sur BRANCH_V8, il doit être fusionné avec BRANCH_V9.

maintenant un des développeurs fait l'erreur suivante : il fusionne tous les changements de BRANCH_V9 en BRANCH_V8 (c.-à-d. une fusion dans la mauvaise direction). De plus, après cette mauvaise fusion, il exécute quelques commits supplémentaires avant de remarquer son erreur.

ainsi la situation est comme indiqué dans le graphique de journal ci-dessous.

o  BRANCH_V8 - 13 - important commit right after the bad merge
|
o    BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|\
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8 (ie. last known good state)
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

Nous pouvons corriger cette erreur comme suit:

  1. mettez à jour votre répertoire local pour le dernier bon état de BRANCH_V8: hg update 11
  2. Créer un nouvel enfant de ce dernier bon état :
    1. modifier un fichier $EDITOR some/file.txt (Ceci est nécessaire car Mercurial ne permet pas les propagations vides)
    2. valider ces modifications hg commit -m "generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9"

      La situation se présente comme suit :
      o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      |
      | o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      | o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |/|
      o |  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      | o  BRANCH_V9 - 10 - last commit on BRANCH_V9
      
  3. fusionner la tête nouvellement générée avec la révision dans laquelle la mauvaise Fusion s'est produite, et jeter tous les changements avant de commettre. ne fusionnez pas simplement les deux têtes, parce que vous perdrez alors l'important commit qui s'est produit après la fusion ainsi!

    1. fusionner : hg merge 12 (ignorer tout conflit)
    2. jeter tous les changements: hg revert -a --no-backup -r 14
    3. valider les modifications : hg commit -m "throwing away wrong merge from BRANCH_V9" La situation ressemble maintenant à :
      o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      |\
      | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | |
      +---o  BRANCH_V8 - 13 - important commit right after the bad merge
      | |
      o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |\|
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      

    Ie. il y a deux têtes sur BRANCH_V8: l'une qui contient le correctif de la mauvaise Fusion, et l'autre qui contient l'important commit de gauche sur BRANCH_V8 qui s'est produit juste après la fusion.

  4. fusionner les deux têtes sur BRANCH_V8 :
    1. fusionner : hg merge
    2. s'engager : hg commit -m "merged two heads used to revert from bad merge"

la situation à la fin sur BRANCH_V8 est maintenant corrigée, et ressemble à ceci:

o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
|\
| o    BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
| |\
| | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
| | |
o | |  BRANCH_V8 - 13 - important commit right after the bad merge
|/ /
o |  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|\|
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

maintenant la situation sur BRANCH_V8 est correcte. Le seul problème restant est que la prochaine fusion de BRANCH_V8 à BRANCH_V9 sera incorrecte, car elle fusionnera dans le "fix" pour la mauvaise fusion comme ce que nous ne voulons pas sur BRANCH_V9. Le truc ici est de fusionner de BRANCH_V8 à BRANCH_V9 dans des modifications séparées :

  • première fusion, de BRANCH_V8 à BRANCH_V9, les changements corrects sur BRANCH_V8 d'avant la mauvaise Fusion.
  • deuxième fusion dans l'erreur de fusion et sa correction, et, sans avoir besoin de vérifier quoi que ce soit, jeter tous les changements
  • Troisièmement fusionner dans les changements restants de BRANCH_V8.

en détail:

  1. changez votre répertoire de travail en BRANCH_V9: hg update BRANCH_V9
  2. fusionner dans le dernier bon état de BRANCH_V8 (ie. la propagation que vous avez générée pour corriger la mauvaise Fusion). Cette fusion est une fusion comme n'importe quelle Fusion régulière, c'est-à-dire. les conflits doivent être résolus, comme d'habitude, et rien ne doit être jeté.
    1. fusionner : hg merge 14
    2. s'engager : hg commit -m "Merging in last good state of BRANCH_V8" Le la situation est maintenant :
      @    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
      |\
      | | o    BRANCH_V8 - 16 - merged two heads used to revert from bad merge
      | | |\
      | +---o  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      | | | |
      | o | |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | | | |
      | | o |  BRANCH_V8 - 13 - important commit right after the bad merge
      | | |/
      +---o  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      | |/
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      
  3. fusionner dans la mauvaise fusion sur BRANCH_V8 + sa correction, et jeter toutes les modifications :
    1. fusionner : hg merge 15
    2. revenir à toutes les modifications: hg revert -a --no-backup -r 17
    3. valider la fusion : hg commit -m "Merging in bad merge from BRANCH_V8 and its fix and throwing it all away" Situation actuelle :
      @    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
      |\
      | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
      | |\
      +-----o  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
      | | | |
      o---+ |  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
      | | | |
      | | o |  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
      | | | |
      +-----o  BRANCH_V8 - 13 - important commit right after the bad merge
      | | |
      o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
      |/ /
      | o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
      | |
      o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
      | |
      
  4. fusionner dans les changements à gauche de BRANCH_V8 :
    1. fusionner : hg merge BRANCH_V8
    2. s'engager : hg commit -m "merging changes from BRANCH_V8"

en fin de compte, la situation ressemble à ceci:

@    BRANCH_V9 - 19 - merging changes from BRANCH_V8
|\
| o    BRANCH_V9 - 18 - Merging in bad merge from BRANCH_V8 and its fix and throwing it all away
| |\
| | o    BRANCH_V9 - 17 - Merging in last good state of BRANCH_V8
| | |\
o | | |  BRANCH_V8 - 16 - merged two heads used to revert from bad merge
|\| | |
| o---+  BRANCH_V8 - 15 - throwing away wrong merge from BRANCH_V9
| | | |
| | | o  BRANCH_V8 - 14 - generating commit on BRANCH_V8 to rectify wrong merge from BRANCH_V9
| | | |
o | | |  BRANCH_V8 - 13 - important commit right after the bad merge
|/ / /
o---+  BRANCH_V8 - 12 - wrong merge from BRANCH_V9
|/ /
| o  BRANCH_V8 - 11 - adding comment on BRANCH_V8
| |
o |  BRANCH_V9 - 10 - last commit on BRANCH_V9
| |

après toutes ces étapes, dans lesquelles vous n'avez pas à vérifier de différence manuellement, BRANCH_V8 et BRANCH_V9 sont corrects, et les fusions futures de BRANCH_V8 à BRANCH_V9 seront également correctes.

50
répondu oenli 2010-01-28 14:34:14

en un clin d'œil, vous pouvez exporter le dépôt vers un tas de diffs, éditer l'historique, puis recoller ensemble ce que vous voulez - dans un nouveau dépôt, donc pas de risque de dommages. Probablement pas trop mal pour votre exemple, mais je ne sais pas à quoi ressemble la vraie histoire.

j'ai référencé cette page en effectuant une opération plus simple:

http://strongdynamic.blogspot.com/2007/08/expunging-problem-file-from-mercurial.html

2
répondu Justin Love 2008-11-06 08:53:03

OK, commencez par faire un nouveau dépôt vide dans un répertoire séparé du dépôt brisé (HG init). Maintenant, allez jusqu'à et incluez la dernière bonne version connue dans le nouveau dépôt; assurez-vous que vous ne pas tirer la mauvaise Fusion et do tirer tout avant elle. Dans l'ancien dépôt, mettez à jour vers la dernière bonne version connue de A, et faites ceci:

hg graft r1 r2 r3

où r1-3 est les changements apportés après la fusion bâclée. Vous pouvez obtenir des conflits à ce point; les corriger.

cela devrait produire de nouvelles modifications par rapport à la dernière bonne version connue d'un . Tirez ces nouveaux changements dans le nouveau référentiel. Juste pour vérifier que vous n'avez rien manqué, faire une arrivée de hg contre l'ancien dépôt. Si vous voyez autre chose que la fusion bâclée et r1-3, Tirez.

jetez l'ancien dépôt. Vous êtes faire. La fusion n'est pas du tout dans le nouveau dépôt et vous n'avez jamais eu à réécrire l'histoire.

2
répondu Kevin 2012-04-18 05:18:39

alors vous voulez fusionner quelques changesets de B en A? Faire marche arrière sur les changements comme vous l'avez fait est une très mauvaise idée que vous avez déjà souffert.

vous devriez utiliser l'extension de transplantation ou avoir une troisième branche où vous faites des changements communs pour fusionner en a et B.

1
répondu 2008-11-06 18:39:54

après beaucoup de discussions avec certaines des personnes utiles sur # mercurial sur freenode, mpm a fourni une partielle solution qui semble fonctionner pour mon cas de test (j'ai généré un faux référentiel essayant de répliquer le scénario)

cependant, sur mon dépôt actuel, pour des raisons que je ne comprends pas tout à fait, il est encore loin d'être parfait.

voici un schéma de la manière actuellement proposée Pour résoudre ce problème:

[image originale perdue]

Son désormais moins d'un problème à résoudre, mais je suis toujours avoir à comparer des diffs ( ie: b46:b11 vs b46:b8 , a43:a10 vs a43:a9 ) et de l'éditer certaines modifications de nouveau.

ne pas fermer cette question / prendre une réponse jusqu'à ce que j'obtienne une façon garantie qui fonctionne sur n'importe quel dépôt.

Important

toute personne essayant ceci les choses devraient cloner leur dépôt et jouer avec comme un bac à sable d'abord. Comme vous devriez le faire avec n'importe quel processus de fusion, parce que de cette façon si ça tourne mal, vous pouvez juste le jeter et recommencer.

1
répondu Kent Fredric 2012-02-24 17:48:14