Abandonner les modifications sans supprimer de l'historique

180

Il y a un commit qui n'a tout simplement pas fonctionné, donc je veux l'abandonner sans le supprimer de l'historique .

J'ai mis à jour à partir d'une révision précédente et engagé, créant ainsi une nouvelle tête.


Je n'ai pas de branches, je ne veux pas de branches, je veux simplement continuer avec la nouvelle tête exactement telle qu'elle est, rien d'extraordinaire, pas de fusion, pas de soucis, continuez juste à oublier la précédente.

Je n'arrive pas à trouver comment faire cela, et je commence à croire que cela ne peut pas être fait. Tout ce que je trouve, ce sont des trucs sur les branches ou des fusions.

o0 '.
la source
1
Il se trouve dans votre dépôt, il n'a donc pas été supprimé de l'historique. Vous avez créé une nouvelle tête, vous pouvez donc continuer à faire des révisions sans vous tromper. Qu'est-ce qui vous empêche de continuer avec la nouvelle tête?
ataylor
Quelle est votre aversion pour les branches?
Andres Jaan Tack
@Andres Ce n'est pas exactement une aversion pour les branches. J'en avais juste besoin pour fonctionner sans une étape supplémentaire stupide de créer un juste pour le fermer.
o0 '.
Quiconque lit - veuillez noter qu'une branche a déjà été créée dans ce scénario; notez l'explication donnée dans cette réponse: stackoverflow.com/a/3692607/3195477
UuDdLrLrSs

Réponses:

181

Mettez à jour votre référentiel vers l'en-tête avec la révision que vous voulez oublier, puis utilisez hg commit --close-branchpour marquer cette branche (anonyme) comme fermée. Ensuite , mettre à jour à la tête de la branche que vous ne voulez, et continuer à travailler.

Vous pouvez toujours voir la branche fermée si vous utilisez l' -coption to hg heads, mais elle n'apparaîtra pas par défaut et hg mergesaura ne pas essayer de fusionner avec la tête fermée.

Vous devrez utiliser hg push --forcela première fois que vous poussez cette tête fermée vers un autre référentiel car vous créez en fait des têtes supplémentaires dans le référentiel distant lorsque vous poussez. Dites donc à Mercurial que tout va bien --force. Les personnes qui tirent la tête fermée ne seront pas dérangées par les avertissements.

Niall C.
la source
3
@Niall C. cela ne fonctionnera-t-il pas seulement s'il l'a marqué comme une branche nommée? Je suppose de ce qu'il dit qu'il a fait qu'il est par défaut
msarchet
mais ... ce n'est pas vrai, les deux têtes sont toujours répertoriées lorsque j'appelle hg heads... J'utilise mercurial 1.4.3, est-ce une nouvelle fonctionnalité?
o0 '.
2
@msarchet: AFAIK, je l'ai essayé aujourd'hui, --close-branch ne fonctionne PAS pour les branches anonymes. Il devrait, mais ne le fait pas. J'espère que cela changera dans une future version de Mercurial. Les branches anonymes sont très agréables, mais devraient être aussi de première classe que les branches nommées.
Krazy Glew
4
@KrazyGlew: Le problème est qu'une branche "anonyme" n'est en réalité qu'une seconde branche avec le même nom que la branche sur laquelle elle était basée. Vous n'essayez pas vraiment de fermer la branche (nommée): vous essayez d'annuler les modifications que vous avez apportées. En d'autres termes, hg branchesdevrait toujours afficher le nom de la branche sur laquelle vous vous trouvez. Plutôt que d'essayer de fermer la branche, fusionnez votre branche anonyme dans la branche d'origine, en annulant toutes les modifications.
StriplingWarrior
2
Dans mon cas, j'ai une branche appelée default (c'est standard) et une autre appelée default / master (je pense qu'en raison du fait que le dépôt distant est en fait git). hg update default / master; hg commit --close-branch; La mise à jour par défaut hg a fonctionné pour moi.
MattD
68

Je sais que vous ne voulez pas travailler avec des succursales à ce stade, mais c'est exactement ce que vous avez fait. Lorsque vous êtes revenu à une version antérieure et que vous avez commis quelque chose qui fonctionnait, vous avez créé une branche - une branche sans nom, mais une branche tout de même.


Il n'y a aucun problème à continuer comme vous êtes et à ne pas vous soucier d'avoir plusieurs têtes, mais si vous voulez ranger les choses pour ne pas choisir accidentellement la mauvaise tête une fois, vous pouvez tuer l'ancienne branche.

Il y a une bonne section dans la documentation Mercurial qui vous présente un certain nombre d'options autour de l' élagage des branches mortes .

Je pense que la meilleure option pour vous est de marquer l'ancienne branche comme "fermée". Si votre ancienne tête est la révision "123", alors:

hg update -r 123
hg commit --close-branch -m 'Closing old branch'
hg update -C default
Nick Pierpoint
la source
3
Blurgh - je viens de voir la réponse de @ Niall après mon entrée. Will upvote Niall et le mien peut languir dans le pool zéro point. :)
Nick Pierpoint
1
J'aime mieux votre réponse, elle nécessite moins de groover sur la terminologie de Merucrial (qui, d'après ce que je peux dire, semble être choisie pour dérouter les utilisateurs de git)
tacaswell
8
lol c'est le contraire! La terminologie de mercurial a été choisie pour sembler naturelle aux utilisateurs de svn, tandis que celle de git est déroutante comme l'enfer! de toute façon, voter pour cette réponse car elle inclut la dernière mise à jour -C
Tobia
2
Pourquoi avez - vous besoin -Cen hg update? Il semblerait qu'aucun fichier n'aurait été modifié, il devrait donc fonctionner sans lui.
max
1
pour autant que je sache, vous n'avez besoin d'un -C nulle part. cependant, si vous avez des modifications en suspens lorsque vous essayez de mettre à jour, vous obtiendrez un abandon.
Eli Albert
21

Tout d'abord, tapez:

hg heads

Imaginez, vous avez trois têtes répertoriées:

changeset:   223:d1c3deae6297
user:        Your name  <[email protected]>
date:        Mon Jun 09 02:24:23 2014 +0200
summary:     commit description #3

changeset:   123:91c5402959z3
user:        Your name <[email protected]>
date:        Sat Dec 23 16:05:38 2013 +0200
summary:     commit description #2

changeset:   59:81b9804156a8
user:        Your name <[email protected]>
date:        Sat Sep 14 13:14:40 2013 +0200
summary:     commit description #1

Disons que vous voulez garder la dernière tête active (223) et fermer le reste.

Vous feriez alors comme suit:

Fermer la tête # 59

hg up -r 59
hg ci --close-branch -m "clean up heads; approach abandoned"

Fermer la tête # 123

hg up -r 123
hg ci --close-branch -m "clean up heads; approach abandoned"

Validez les changements

hg push

N'oubliez pas de passer à la bonne tête à la fin

hg up -r 223

Et tu as fini.

Artur Barseghyan
la source
C'est un bon tutoriel, mais les exemples de messages de validation sont un peu méta. J'inclurais de meilleurs exemples afin que ceux qui apprennent de vous puissent fournir de meilleurs messages de validation. Quelque chose comme --close-branch -m "Closing branch - technique #2 abandoned in favor of technique #3".
Jason R. Coombs
5
De plus, vous avez terminé en quelque sorte à la fin, sauf que votre copie de travail est toujours sur la tête que vous venez de fermer. Commettre un autre changement se produirait sur la tête fermée, la rouvrant. Vous voudrez hg up -r 223avant d'apporter des modifications.
Jason R. Coombs
@Jason R. Coombs: C'est vrai!
Artur Barseghyan
Selon @Niall, et ma propre expérience à l'instant, vous aurez besoin hg push --force, pas seulement hg pushde passer l'avertissement concernant le fait de pousser plusieurs têtes.
craq
1
@Artur je suis d'accord en général. Dans ce cas, hg pushen soi ne fonctionnait pas pour moi. Comment recommandez-vous de pousser les modifications vers un repo externe s'il refuse en raison de plusieurs têtes?
craq
12

Vous souhaitez utiliser hg backout. Cela supprime les modifications apportées par l'ensemble de modifications de tout ensemble de modifications enfant.

Vérifiez ceci pour une bonne explication. Désactivation Mercurial

msarchet
la source
2
C'est exactement la bonne réponse. Backout ajoute l'inverse d'un ensemble de modifications, annulant le fonctionnement et vous donnant un message de validation pour vous rappeler pourquoi vous n'avez pas aimé l'idée.
Ry4an Brase du
7
En fait, je ne suis pas d'accord - abandonner le travail sur une seule tête et recommencer à partir d'un bon point de départ semble être un modèle de travail plus propre que d'utiliser des retraits. Surtout que vous ne pouvez pas annuler plus d'un changesets à la fois.
Martin Geisler
1
@Martin Geisler, eh bien, je suis d'accord avec cela en général, mais l'OP a déclaré qu'il voulait abandonner les changements sans branches
msarchet
2
@Martin Geisler oui je suis tout à fait pour la branchement, juste parfois, nuancer un mauvais changement est le meilleur
msarchet
1
cela peut être utile parfois, mais ce n'était pas vraiment ce que je voulais. Merci quand même :)
o0 '.
2

Les réponses de Niall et de Nick sont directes. Parce que je me surprends à créer beaucoup de têtes pendantes, j'ai fini par écrire un alias pour fermer les têtes plus facilement. En ajoutant ceci à votre .hgrc:

[alias]
behead = !REV=$($HG id -i); $HG update $@ -q && $HG ci --close-branch -m "Closing dead head" && $HG update $REV -q

(si vous avez déjà une [alias]section, vous pouvez y ajouter à la place)

Vous pouvez maintenant fermer une tête en une seule commande (et sans avoir à mettre à jour manuellement un ensemble de modifications différent) comme ceci:

$ hg behead 123

Remarque: l'alias tire parti du fait que les alias Mercurial peuvent être des commandes shell . Cela signifie que cela ne fonctionnera probablement que sous UNIX, pas sous Windows.

jjst
la source
2

Une alternative à la fermeture ou à la suppression de la branche indésirable serait de la fusionner d'une manière qui élimine totalement ses effets, mais la laisse dans l'histoire. Cette approche permettra à ces changements indésirables de se propager dans une poussée - utilisez donc ceci uniquement si c'est l'effet recherché.

Disons que l'historique des modifications ressemble à ceci:

1-2-3-4-5-6    
       \    
        7-8-*

et c'est 5et 6qui ne sont plus voulus.

Tu peux le faire:

hg up 8
hg merge -r 6 -t :local
hg commit ...

ce qui créera ceci:

1-2-3-4-5-6    
       \   \
        7-8-9-*

La mise à jour 8garantit que vous travaillez à la tête souhaitée dans l'histoire, que vous souhaitez conserver.

Le -t :localhg demande à hg d'utiliser l '"outil" de fusion appelé local qui lui dit d'ignorer les changements de l'autre branche, c'est-à-dire celle qui n'est PAS représentée par l'état actuel du dossier de travail. Plus d'infos .

Ainsi, les changements indésirables dans 5et 6sont préservés dans l'histoire mais n'affectent rien de plus récent.

UuDdLrLrSs
la source
2

Il s'agit d'un cas d'utilisation de l' extension Evolve . Il n'est actuellement pas fourni avec Mercurial, il s'agit donc techniquement d'une extension tierce. Mais il est largement utilisé par un groupe de personnes, y compris les développeurs Mercurial, est en cours de développement très actif et ne mène nulle part.

Avec l'extension Evolve, vous faites simplement

hg prune -r revname

et continue ta vie. Le cset sera toujours là, mais obsolète. Il ne sera pas visible à moins que vous ne passiez l' --hiddenoption aux commandes Mercurial, et par défaut, il ne sera pas poussé vers les référentiels distants. Bien que je pense que vous pouvez le forcer si vous le voulez vraiment.

Si le cset que vous élaguez a des ancêtres que vous souhaitez conserver, vous devrez alors exécuter hg evolvepour rebaser ces changesets. hg evolvele fera automatiquement. Sinon, vous n'avez rien à faire.

Faheem Mitha
la source
1

Vous pouvez cloner votre dépôt corrompu vers un nouveau sans cloner cette tête indésirable. Supprimez ensuite l'ancien référentiel, déplacez le clone nouvellement créé vers l'emplacement d'origine et continuez à l'utiliser. Cela prendra du temps, mais vous obtiendrez un référentiel parfaitement propre sans signe de cette révision indésirable.

hg clone --rev myGoodResition myDirtyRepo myCleanRepo
kjam
la source
1
Ce n'est absolument pas ce que j'ai demandé, désolé.
o0 '.
4
@Kristof: est-ce une blague? Relisez la première ligne de mon message: "abandonnez-le sans le supprimer de l'historique "
o0 '.
-1

J'ai rencontré ce problème à plusieurs reprises lorsque je veux décapiter une tête créée par erreur. Je veux toujours le voir disparaître de la surface de la Terre.

Sur votre copie locale, obtenez la dernière version, puis:

  1. Trouvez le début d'une tête que vous souhaitez dénuder (où un nouveau cou commence à se ramifier), obtenez le numéro de révision

  2. Déshabillez-le.


Source: TipsAndTricks .

Source: PruningDeadBranches # Using_strip .

hg --config extensions.hgext.mq= strip -n <rev>
  1. Faites une mise à jour de fichier triviale (ajoutez un espace blanc à un fichier), validez et envoyez.

Votre repo devrait maintenant avoir la tête dépouillée. La dernière étape est importante car le décapage ne crée aucune modification que vous pouvez pousser vers votre référentiel central. Sans la dernière étape, vous n'avez décapé la tête que localement.

sonjz
la source
1
Mais, pousser ne supprime jamais rien du référentiel distant. Cela n'ajoute jamais que des informations. Si l'ensemble de modifications est déjà sur le référentiel central, vous devez soit utiliser l'extension evolve, soit la supprimer d'une manière ou d'une autre sur le serveur central lui-même. Si l'ensemble de modifications n'est pas déjà sur le référentiel central, le supprimer localement suffira sans qu'aucune poussée ne soit nécessaire.
Ben