Table of Contents
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.
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:
(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.
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.
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.
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
.
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.
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.
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.
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.
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.
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.
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 |
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`