Appendix A. Migrer vers Mercurial

Table of Contents

A.1. Importer l'historique depuis un autre système
A.1.1. Convertir plusieurs branches
A.1.2. Associer les noms d'utilisateurs
A.1.3. Nettoyer l'arboresence
A.1.4. Améliorer les performances de la conversion Subversion
A.2. Migrer depuis Subversion
A.2.1. Différences philosophiques
A.2.2. Références des commandes
A.3. Conseils utiles pour les débutants

Une manière courante de s'essayer à un nouveau gestionnaire de révisions est d'expérimenter en migrant un projet existant, plutôt que le faire avec un nouveau projet.

Dans cette annexe, nous discuterons comment importer l'historique d'un projet dans Mercurial, et à quoi faire attention si vous êtes habitués à un autre outil de gestion de révisions.

A.1. Importer l'historique depuis un autre système

Mercurial est livré avec une extension nommée convert, qui permet d'importer un historique depuis les gestionnaire de révisions les plus courants. Au moment de l'écriture de ce livre, il pouvait importer l'historique depuis:

  • Subversion

  • CVS

  • git

  • Darcs

  • Bazaar

  • Monotone

  • GNU Arch

  • Mercurial

(Pour savoir pourquoi Mercurial lui même est supporté comme source, voir Section A.1.3, “Nettoyer l'arboresence”.)

Vous pouvez activer l'extension de la manière habituelle, en éditant votre fichier ~/.hgrc

[extensions]
convert =

Ceci rendra la commande hg convert disponible. La commande est facile à utiliser. Par exemple, la commande suivante va importer l'historique Subversion du framework de test Nose Unit dans Mercurial.

$ hg convert http://python-nose.googlecode.com/svn/trunk

L'extension convert opère de manière incrémentale. En d'autres mots, après une première exécution de la commande hg convert, les exécutions ultérieures importeront les révisions ultérieures à l'exécution précédente. La conversion incrémentale ne réussira que si vous exécutez hg convert dans le même dépôt que vous aviez utilisé à l'origine, ceci parce que l'extension convert sauvegarde un certain nombre de méta-données privées dans le fichier .hg/shamap (non versioné) au sein du dépôt cible.

Lorsque vous voulez faire des modifications en utilisant Mercurial, le mieux est de faire un clone de l'ensemble de l'arborescence que vous souhaitez convertir, et de laisser l'arborescence d'origine pour de futures conversions incrémentales. C'est la manière la plus sûre pour vous laisser récupérer et fusionner les modifications futures depuis l'outil de gestion de révisions dans votre nouveau dépôt Mercurial.

A.1.1. Convertir plusieurs branches

La commande hg convert citée ci-dessus convertit seulement l'historique de la branche principale (trunk) du dépôt Subversion. Si nous utilisons à la place l'URL http://python-nose.googlecode.com/svn, Mercurial va automatiquement détecter la branche principale (trunk), les étiquettes (tags), et les branches que les dépôts Subversion utilisent généralement, et les importera chacun dans une branche Mercurial distincte.

Par défaut, chaque branche Subversion importée dans Mercurial se voit attribuer un nom de branche. Une fois la conversion achevée, vous pouvez obtenir la liste des noms des branches actives dans le dépôt Mercurial en utilisant la commande hg branches -a. Si vous préférez importer les branches Subversion sans noms, ajoutez l'option --config convert.hg.usebranches=false à la commande hg convert.

Une fois votre arborescence convertie, si vous souhaitez travailler selon la pratique habituelle sous Mercurial avec une arborescence qui ne contient qu'une seule branche, vous pouvez cloner cette seule branche en utilisant hg clone -r nomdemabranche.

A.1.2. Associer les noms d'utilisateurs

Certains outils de gestion de révisions ne sauvegardent, avec les modifications, que les noms d'utilisateurs raccourcis. Ceux-ci peuvent être difficiles à interpréter. La norme avec Mercurial est de sauvegarder le nom du committeur et son adresse mail, ce qui est beaucoup plus utile pour discuter avec lui par la suite.

Si vous convertissez une arborescence depuis un gestionnaire de révisions qui utilise seulement les noms raccourcis, vous pouvez associer ces noms à des équivalents plus détaillés en passant l'option --authors à la commande hg convert. Cette option attend un fichier qui contient des entrées sous la forme suivante:

arist = Aristotle <aristotle@phil.example.gr>
soc = Socrates <socrates@phil.example.gr>

Quand convert trouve une modification associée au nom arist dans le dépôt de source, il va utiliser le nom Aristotle <aristotle@phil.example.gr> dans les révisions Mercurial. Si aucune correspondance n'est trouvé, il utilise le nom tel quel.

A.1.3. Nettoyer l'arboresence

Tous les projets n'ont pas un historique parfait. Il peut y avoir des répertoires qui n'auraient jamais dû être ajoutés, un fichier qui est trop volumineux, ou même une partie de la hiérarchie qui devrait être réorganisée.

L'extension convert permet d'utiliser un fichier d'association qui peut réorganiser les fichiers et les répertoires dans un projet lors de l'importation de son historique. Ceci est utile non seulement quand vous importez l'historique d'un autre gestionnaire de révisions, mais aussi pour nettoyer ou réorganiser l'arborescence d'un projet Mercurial.

Pour indiquer le fichier d'association, on utilise l'option --filemap en lui fournissant un nom de fichier. Le fichier d'association contient des lignes de la forme suivante :

# Ceci est un commentaire.
# Les lignes vides sont ignorées.

include path/to/file

exclude path/to/file

rename from/some/path to/some/other/place

La directive include inclut un fichier, ou l'ensemble des fichiers d'un répertoire, dans le dépôt de destination. La directive exclude omet les fichiers ou répertoires du dépôt. Ceci inclut aussi les autres fichiers et répertoires qui ne sont pas explicitement inclus. La directive exclude entraine l'omission des fichiers ou répertoires, et autres fichiers qui ne sont pas explicitement inclus.

Pour déplacer un fichier ou un répertoire d'un emplacement à un autre, utilisez la directive rename. Si vous avez besoin de déplacer un fichier ou un répertoire depuis un sous répertoire dans la racine du dépôt, utilisez . comme second argument de la directive rename.

A.1.4. Améliorer les performances de la conversion Subversion

Vous aurez souvent besoin de plusieurs essais avant d'arriver à la parfaite combinaison de fichier d'association de fichiers, de fichier d'association de noms d'utilisateurs et des autres paramètres. Or, convertir un dépôt Mercurial via un protocole comme ssh ou http peut être des milliers de fois plus long que ce dont le système d'exploitation est en fait capable de faire, à cause des latence réseau. Ceci peut rendre la conception de cette combinaison parfaite très douloureuse.

La commande svnsync peut grandement améliorer la vitesse de conversion d'un dépôt Subversion. Il s'agit d'un programme de miroir de dépôt Subversion en lecture seule. L'idée est de créer un miroir local d'une arborescence Subversion, puis de convertir ce miroir en dépôt Mercurial.

Supposez que nous voulions convertir le dépôt Subversion du populaire projet Memcached en une arborescence Mercurial. Tout d'abord, nous créons un dépôt Subversion local.

$ svnadmin create memcached-mirror

Puis, nous allons mettre en place un hook Subversion dont svnsync a besoin.

$ echo '#!/bin/sh' > memcached-mirror/hooks/pre-revprop-change
$ chmod +x memcached-mirror/hooks/pre-revprop-change

Nous initialisons ensuite svnsync dans ce dépôt.

$ svnsync --init file://`pwd`/memcached-mirror \
  http://code.sixapart.com/svn/memcached

La prochaine étape est de commencer le processus de mirroring de svnsync.

$ svnsync sync file://`pwd`/memcached-mirror

Enfin, nous importons l'historique de notre dépôt local Subversion dans Mercurial.

$ hg convert memcached-mirror

Nous pouvons utiliser ce processus de manière incrémentale, si le dépôt Subversion est toujours en activité. Il suffit d'exécuter de nouveau svnsync pour récupérer les récentes modifications dans notre miroir, puis hg convert les importe dans notre arborescence Mercurial.

Il y a deux avantages à utiliser un import à deux étages comme avec svnsync. Le premier est qu'il utilise du code de synchronisation réseau de Subversion plus efficace que la commande hg convert, et donc transfère moins de données par le réseau. Le deuxième est que l'import depuis un dépôt Subversion local est si rapide que vous pouvez peaufiner et réitérer les paramètres de conversion de ce dernier sans souffrir de la qualité de la connexion réseau.

A.2. Migrer depuis Subversion

Subversion est le système de gestion de versions open source le plus populaire aujourd'hui. Bien qu'il y ait des différences entre Mercurial et Subversion, faire la transition de l'un à l'autre n'est pas très difficile. Les deux disposent en effet de jeux de commandes similaires et d'interfaces similaires.

A.2.1. Différences philosophiques

La différence fondamentale entre Subversion et Mercurial est bien évidement que Subversion est centralisé, alors que Mercurial est distribué. Puisque que Mercurial enregistre tout l'historique d'un projet sur votre disque dur local, il n'a besoin d'effectuer des accès au réseau que lorsque vous voulez explicitement communiquer avec un autre dépôt. Subversion, par contre, ne conserve que peu d'informations localement, et le client doit donc communiquer avec le serveur central pour la plupart des opérations communes.

Subversion s'en tire plus ou moins bien sans notion de branche réellement bien définie : quelle portion de l'espace de nommage du serveur est une branche est une simple question de convention, le logiciel n'imposant rien à ce sujet. Mercurial considère un dépôt comme un élément de la gestion des branches.

A.2.1.1. Portée des commandes

Puisque que Subversion ne sait pas réellement quelle partie de son espace de nommage est en fait une branche, il traite la plupart des commandes comme des requêtes à exécuter sur le répertoire où vous vous situez, et ses sous répertoires. Par exemple, si vous exécutez svn log, vous verrez l'historique de la partie de l'arborescence où vous vous situez, et non de la hiérarchie entière.

Les commandes de Mercurial ont un comportement différent : toutes les commandes s'appliquent à l'ensemble de l'arborescence du dépôt. Exécutez la commande hg log et elle vous donnera l'historique de l'ensemble de l'arborescence, quel que soit le sous-répertoire où vous vous situez. Si vous souhaitez obtenir l'historique d'un répertoire ou seulement d'un fichier, ajouter simplement le nom de celui-ci à la commande, par exemple hg log src.

De ma propre expérience, cette différence dans leur comportement par défaut est probablement ce qui risque de vous surprendre le plus si vous passez régulièrement d'un outil à l'autre.

A.2.1.2. Opération multi utilisateur et sécurité

Avec Subversion, il est normal (bien que légèrement désapprouvé) que différentes personnes collaborent sur une seule branche. Si Alice et Bob travaillent ensemble, et Alice ajoute ses modifications à leur branche partagée, Bob doit alors mettre à jour sa vue de la branche avant de pouvoir appliquer un commit. Puisqu'il n'a, à ce moment, pas effectué de commit des modifications qu'il a faites, il se peut qu'il ne corrompe ou ne perde ses modifications pendant ou après la mise à jour.

Mercurial encourage, à l'inverse, un modèle "commit-puis-merge". Avant de récupérer des modifications depuis le serveur, ou avant d'y envoyer les siennes, Bob enregistre ses modifications de manière locale en appliquant un commit. C'est à dire que si Alice avait envoyé ses modifications sur le serveur avant que Bob n'envoie les siennes, ce dernier ne pourra le faire qu'après avoir récupéré et fusionné celles d'Alice avec les siennes. Si Bob fait alors une erreur lors de la fusion, il pourra toujours restaurer sa version, pour laquelle il avait appliqué le commit.

Il est important de souligner qu'il s'agit de la manière habituelle de travailler avec ces outils. Subversion propose une manière plus sûre de "travailler-dans-votre-propre-branche", mais elle est assez complexe pour que, en pratique, elle ne soit que rarement utilisé. Mercurial propose de son côté un mode un peu moins sûr, permettant de récupérer des modifications par dessus des modifications non committées, qui reste toutefois très peu répandu.

A.2.1.3. Publication vs changement locaux

Une commande Subversion svn commit publie immédiatement les modifications sur le serveur, où elles peuvent être vu par n'importe qui doté d'un privilège de lecture.

Avec Mercurial, les modifications sont toujours d'abord enregistrées localement, et doivent être par la suite transférés par la commande hg push.

Chaque approche a ses avantages et ses inconvénients. Le modèle Subversion implique que les modifications soient publiées, et donc disponibles immédiatement. D'un autre coté, cela implique aussi que, pour pouvoir utiliser le logiciel normalement, un utilisateur doit avoir les droits d'écriture dans le dépôt, et ce privilège n'est pas concédé facilement par la plupart des projets Open Source.

L'approche de Mercurial permet à quiconque de faire un clone du dépôt et d'y ajouter ses modifications sans jamais avoir besoin de la permission de quiconque, et l'on peut même publier ses modifications et continuer à participer comme on le désire. Toutefois, la distinction entre les commits et le transfert de ces derniers présente le risque que quelqu'un applique ses modifications par un commit local sur son portable et parte se promener pendant quelques jours en ayant oublié de les transférer, ce qui peut, dans certains rares cas, bloquer temporairement ses collaborateurs.

A.2.2. Références des commandes

Table A.1. Commandes Subversion et leurs équivalents Mercurial

Subversion Mercurial Notes
svn add hg add  
svn blame hg annotate  
svn cat hg cat  
svn checkout hg clone  
svn cleanup n/a Aucun nettoyage nécessaire.
svn commit hg commit; hg push hg push publie les modifications après un commit.
svn copy hg clone Pour créer une nouvelle branche
svn copy hg copy Pour copier des fichiers ou des répertoires
svn delete (svn remove) hg remove  
svn diff hg diff  
svn export hg archive  
svn help hg help  
svn import hg addremove; hg commit  
svn info hg parents Affiche la version sur la base de laquelle on travaille
svn info hg showconfig paths.default Affiche de quelle URL est extrait ce dépôt
svn list hg manifest  
svn log hg log  
svn merge hg merge  
svn mkdir n/a Mercurial ne versionne pas les répertoires
svn move (svn rename) hg rename  
svn resolved hg resolve -m  
svn revert hg revert  
svn status hg status  
svn update hg pull -u  

A.3. Conseils utiles pour les débutants

Avec la plupart des gestionnaire de versions, afficher un diff associé à une révision peut être assez douloureux. Par exemple, avec Subversion, pour voir ce qui a été modifiée dans la révision 104654, vous devez saisir svn diff -r104653:104654. Mercurial élimine le besoin de saisir l'identifiant d'une révision deux fois dans ce cas classique. Pour un simple diff, hg export 104654 suffit. Pour obtenir une entrée du journal suivie d'un diff, hg log -r104654 -p.

Quand vous exécutez la commande hg status sans aucun argument, elle affiche l'état de l'ensemble de l'arborescence, avec des chemins relatifs partant de la racine du dépôt. Ceci rend difficile de copier un nom de fichier depuis la sortie de la commande hg status dans une autre ligne de commande. Si vous fournissez un fichier ou un répertoire à la commande hg status, elle va afficher les chemins relatif depuis votre répertoire courant à la place. Ainsi, pour avoir un état sur l'ensemble de l'arborescence à l'aide de hg status, avec des chemins relatifs à votre répertoire courant, et non la racine du dépôt, ajoutez la sortie de hg root à la commande hg status. Vous pouvez le faire aisément sur un système Unix ainsi :

$ hg status `hg root`