Mercurial: comment modifier le dernier commit?

211

Je recherche une contrepartie git commit --amenddans Mercurial, c'est-à-dire un moyen de modifier le commit auquel ma copie de travail est liée. Je ne suis intéressé que par le dernier commit, pas par un commit antérieur arbitraire.

Les exigences de cette procédure de modification sont les suivantes:

  • si possible, il ne devrait nécessiter aucune extension. Il ne doit pas nécessiter d'extensions autres que celles par défaut , c'est-à-dire des extensions qui ne sont pas fournies avec une installation Mercurial officielle.

  • si l'engagement de modification est un responsable de ma branche actuelle, aucun nouveau responsable ne doit être créé. Si le commit n'est pas head, un nouveau head peut être créé.

  • la procédure doit être sécurisée de telle sorte que si, pour une raison quelconque, la modification échoue, je souhaite que le même état de copie de travail et de référentiel soit restauré qu'avant la modification. En d'autres termes, si la modification elle-même peut échouer, il devrait y avoir une procédure de sécurité intégrée pour restaurer l'état de la copie de travail et du référentiel. Je fais référence aux "échecs" qui relèvent de la nature de la procédure de modification (comme par exemple les conflits), pas aux problèmes liés au système de fichiers (comme les restrictions d'accès, le fait de ne pas pouvoir verrouiller un fichier pour l'écriture, ... )

Mise à jour (1):

  • la procédure doit être automatisable , afin qu'elle puisse être effectuée par un client GUI sans aucune interaction utilisateur requise.

Mise à jour (2):

  • les fichiers du répertoire de travail ne doivent pas être touchés (il peut y avoir des verrous du système de fichiers sur certains fichiers modifiés). Cela signifie notamment qu'une approche possible ne peut à aucun moment nécessiter un répertoire de travail propre.
mstrap
la source

Réponses:

289

Avec la version de Mercurial 2.2 , vous pouvez utiliser l' --amendoption avec hg commitpour mettre à jour le dernier commit avec le répertoire de travail actuel

À partir de la référence de la ligne de commande :

L'indicateur --amend peut être utilisé pour modifier le parent du répertoire de travail avec une nouvelle validation qui contient les modifications du parent en plus de celles actuellement signalées par hg status, le cas échéant. L'ancien commit est stocké dans un bundle de sauvegarde dans .hg / strip-backup (voir bundle d'aide hg et aide hg à dégrouper pour savoir comment le restaurer).

Le message, l'utilisateur et la date sont extraits du commit modifié, sauf indication contraire. Lorsqu'un message n'est pas spécifié sur la ligne de commande, l'éditeur s'ouvre avec le message du commit modifié.

Ce qui est génial, c'est que ce mécanisme est "sûr", car il s'appuie sur la fonction "Phases" relativement nouvelle pour empêcher les mises à jour qui changeraient l'historique qui a déjà été rendu disponible en dehors du référentiel local.

Chris Phillips
la source
2
Bonne réponse! L' extension évolutive expérimentale vous permet de modifier en toute sécurité les validations non-head . L'ancien commit sera marqué comme obsolète et masqué. Avec un serveur non-éditeur, vous pouvez même le faire en toute sécurité après avoir poussé les ensembles de modifications.
Martin Geisler
5
Pour mettre à jour le message sur le dernier commit: hg commit --amend -m "c'est mon nouveau message"
Jay Sheth
52

Vous avez 3 options pour modifier les validations dans Mercurial:

  1. hg strip --keep --rev -1annulez le (s) dernier (s) commit (s), vous pouvez donc recommencer (voir cette réponse pour plus d'informations).

  2. Utilisation de l' extension MQ , fournie avec Mercurial

  3. Même si elle n'est pas livrée avec Mercurial, l' extension Histedit mérite d'être mentionnée

Vous pouvez également consulter la page Historique de modification du wiki Mercurial.

En bref, l'édition de l'historique est vraiment difficile et découragée . Et si vous avez déjà poussé vos modifications, vous ne pouvez presque rien faire, sauf si vous avez le contrôle total de tous les autres clones.

Je ne connais pas vraiment la git commit --amendcommande, mais AFAIK, Histedit est ce qui semble être l'approche la plus proche, mais malheureusement, elle n'est pas livrée avec Mercurial. MQ est vraiment compliqué à utiliser, mais vous pouvez presque tout faire avec.

krtek
la source
1
Je ne sais pas pourquoi j'ai raté le rollback, mais il semble faire (presque) ce que je veux. Le seul problème est que lorsqu'un fichier a été supprimé pour ma validation d'origine et qu'il a été ressuscité pour ma validation modifiée: avant la restauration, il sera non versionné, après la restauration, il sera planifié pour la suppression (mais le fichier existe toujours dans le répertoire de travail)
mstrap
@Marc Je ne suis pas sûr de comprendre votre problème, mais jetez un œil à la commande oublier, je pense que c'est ce que vous recherchez.
krtek
Je ne pense pas que "oublier" sera utile ici. Voici le problème plus en détail: (1) Je suis à la révision 2 (2) Supprimer le "fichier" et avoir d'autres modifications (3) Valider les modifications, entraînant la révision 3 (4) Maintenant, je vais changer d'avis et décider "file" ne doit pas être supprimé du commit, donc je veux modifier la révision 3. Par conséquent, je vais ajouter à nouveau "file" qui est maintenant non versionné (5) Maintenant, je fais un rollback: il réinitialisera le dirstate et marquera " fichier "comme supprimé. (6) Lorsque vous effectuez à nouveau "hg commit", "file" restera tel qu'il a été supprimé, bien qu'il ne devrait plus l'être. À quoi pourrait ressembler un correctif automatisé?
mstrap
1
Pour la partie automatisée, je ne sais pas, mais vous pouvez faire hg revert myfilepour annuler la suppression. Peut-être ré-ajouter avec hg addle fichier après le rollbackfonctionne également.
krtek
3
Je suis d'accord que la modification de l'historique des modifications publiées doit être évitée, mais la modification de mon historique local est l'un des points forts d'un DVCS. MQ avec son qimport est un pur montage historique, AFAICT.
mstrap
38

Équivalent GUI pour hg commit --amend:

Cela fonctionne également à partir de l'interface graphique de TortoiseHG (j'utilise la v2.5):

Passez à la vue «Valider» ou, dans la vue du plan de travail, sélectionnez l'entrée «Répertoire de travail». Le bouton «Valider» a une option nommée «Modifier la révision actuelle» (cliquez sur la flèche déroulante du bouton pour la trouver).

entrez la description de l'image ici

          ||
          ||
          \/

entrez la description de l'image ici

Caveat emptor :

Cette option supplémentaire ne sera activée que si la version mercurial est au moins 2.2.0, et si la révision actuelle n'est pas publique, n'est pas un correctif et n'a pas d'enfants. [...]

Cliquer sur le bouton appellera «commit --amend» pour «modifier» la révision.

Plus d'informations à ce sujet sur la chaîne de développement THG

Cristian Diaconescu
la source
Très utile, merci. THG est assez intelligent pour transférer par défaut le message de validation (modification) au message de la validation précédente - exactement ce que je voulais.
UuDdLrLrSs
7

Je suis à l'écoute de ce que krtek a écrit. Plus spécifiquement, solution 1:

Hypothèses:

  • vous avez validé un (!) ensemble de modifications mais ne l'avez pas encore poussé
  • vous souhaitez modifier cet ensemble de modifications (par exemple, ajouter, supprimer ou modifier des fichiers et / ou le message de validation)

Solution:

  • utiliser hg rollbackpour annuler le dernier commit
  • engager à nouveau avec les nouveaux changements en place

La restauration annule vraiment la dernière opération. Sa façon de travailler est assez simple: les opérations normales dans HG ne s'ajouteront qu'aux fichiers; cela inclut un commit. Mercurial garde une trace de la longueur des fichiers de la dernière transaction et peut donc annuler complètement une étape en tronquant les fichiers à leur ancienne longueur.

Lucero
la source
1
Merci pour la solution de réglage (1); il y a juste un petit problème avec la restauration, veuillez voir mon commentaire sur la solution de krtek.
mstrap
8
Une chose à souligner sur le retour en arrière, car cela attire les gens, c'est que c'est la dernière transaction du dépôt qui est annulée, pas le dernier commit. Donc, si quelque chose d'autre a provoqué une écriture dans le référentiel, la restauration n'aidera pas. C'est une chose subtile mais importante à retenir. MQ et histedit peuvent vous aider une fois la fenêtre de restauration fermée, mais toujours jusqu'à un certain point.
Paul S
7

En supposant que vous n'avez pas encore propagé vos modifications, voici ce que vous pouvez faire.

  • Ajoutez à votre .hgrc:

    [extensions]
    mq =
    
  • Dans votre référentiel:

    hg qimport -r0:tip
    hg qpop -a
    

    Bien sûr, vous n'avez pas besoin de commencer par la révision zéro ou de supprimer tous les correctifs, car la dernière seule pop ( hg qpop) suffit (voir ci-dessous).

  • supprimez la dernière entrée du .hg/patches/seriesfichier ou les correctifs que vous n'aimez pas. La réorganisation est également possible.

  • hg qpush -a; hg qfinish -a
  • supprimez les .difffichiers (correctifs non appliqués) toujours dans .hg / correctifs (devrait être l'un dans votre cas).

Si vous ne voulez pas reprendre tout votre patch, vous pouvez le modifier en utilisant hg qimport -r0:tip(ou similaire), puis éditer des trucs et utiliser hg qrefreshpour fusionner les modifications dans le patch le plus haut de votre pile. Lisez hg help qrefresh.

En éditant .hg/patches/series, vous pouvez même supprimer plusieurs correctifs ou en réorganiser certains. Si votre dernière révision est 99, vous pouvez simplement utiliser hg qimport -r98:tip; hg qpop; [edit series file]; hg qpush -a; hg qfinish -a.

Bien sûr, cette procédure est fortement déconseillée et risquée . Faites une sauvegarde de tout avant de faire cela!

En tant que sidenote, je l'ai fait des millions de fois sur des référentiels privés uniquement.

hochl
la source
J'avais également envisagé d'utiliser mq-extension, mais cela nécessite de nombreuses opérations pour lesquelles certaines d'entre elles peuvent échouer (par exemple, si des fichiers binaires sont impliqués). De plus, avoir à éditer .hg / patch / series ne sera pas acceptable, car cette procédure doit être utilisée dans un client GUI (j'ai mis à jour les exigences ci-dessus)
mstrap
Hmmm, désolé que ce ne soit pas pour vous, sur un référentiel privé, cela botte vraiment le cul (avec les sauvegardes - j'ai déjà détruit un représentant avec lui ^^). C'est assez cool de combiner des patchs en un seul avant de pousser les changements locaux en utilisant hg qfold, btw
hochl
+1 pour l'utilisation de MQ, mais je pense que vous êtes allé trop loin. Il demande seulement de modifier le dernier commit. De plus, cette importation disparaîtra dès qu'elle atteindra une fusion. 'qimport -r tip; <modifier des trucs>; qrefresh -e; qfin -a 'fera le travail (-e pour éditer le message de commit)
Paul S
c'est vrai, les fusions sont un problème, je n'utilise généralement qu'un seul patch et je l'utilise hg import -r<prev>:tip. Un pitoyable il n'y a pas de raccourci pour la version précédente, comme dans subversion.
hochl
2

Les versions récentes de Mercurial incluent l' evolveextension qui fournit la hg amendcommande. Cela permet de modifier un commit sans perdre l'historique de pré-modification dans votre contrôle de version.

hg modifier [OPTION] ... [FICHIER] ...

alias: actualiser

combiner un ensemble de modifications avec des mises à jour et le remplacer par un nouveau

Commits a new changeset incorporating both the changes to the given files
and all the changes from the current parent changeset into the repository.

See 'hg commit' for details about committing changes.

If you don't specify -m, the parent's message will be reused.

Behind the scenes, Mercurial first commits the update as a regular child
of the current parent. Then it creates a new commit on the parent's
parents with the updated contents. Then it changes the working copy parent
to this new combined changeset. Finally, the old changeset and its update
are hidden from 'hg log' (unless you use --hidden with log).

Voir https://www.mercurial-scm.org/doc/evolution/user-guide.html#example-3-amend-a-changeset-with-evolve pour une description complète de l' evolveextension.

Karl Bartel
la source
Réutiliser le même message de validation est une fonctionnalité intéressante!
mpen
1

Cela ne résoudra peut-être pas tous les problèmes de la question d'origine, mais comme cela semble être le post de facto sur la façon dont mercurial peut modifier le commit précédent, j'ajouterai mes 2 cents d'informations.

Si vous êtes comme moi et que vous souhaitez uniquement modifier le message de validation précédent (corriger une faute de frappe, etc.) sans ajouter de fichiers, cela fonctionnera

hg commit -X 'glob:**' --amend

Sans aucun motif d'inclusion ou d'exclusion hg commit, tous les fichiers du répertoire de travail seront inclus par défaut. L'application d'un modèle -X 'glob:**'exclura tous les fichiers possibles, ne permettant que de modifier le message de validation.

Fonctionnellement, c'est la même chose que git commit --amendlorsqu'il n'y a pas de fichiers dans l'index / l'étape.

kaskelotti
la source
0

Une autre solution pourrait être d'utiliser la uncommitcommande pour exclure un fichier spécifique de la validation en cours.

hg uncommit [file/directory]

Ceci est très utile lorsque vous souhaitez conserver la validation actuelle et désélectionner certains fichiers de la validation (particulièrement utile pour files/directoriesavoir été supprimé).

Sam Liao
la source