Pourquoi je préfère Mercurial
À l’heure de l’externalisation massive, du “social coding“, du cloud computing ou encore d’autres joyeusetés “mainstream” beaucoup d’entre nous sommes passés à GitHub, bitbucket ou d’autres services d’hébergement.
Il est vrai que Git domine largement le marché de nos jours et ce, sans doute grâce à Github. Néanmoins, dans cet article je vais expliquer pourquoi j’utilise Mercurial et que je ne suis pas prêt de changer.
Avant de vous donner mes raisons, je tiens à préciser que Mercurial est le premier SCM que j’ai utilisé massivement depuis environ 2008. Je n’ai jamais changé depuis bien que j’ai déjà essayé quelques autres comme git, fossil.
Cet article risque d’être très subjectif, je ne dénigre en aucun cas Git, je vais le comparer le plus objectivement possible. Tout ce que je dirai sur Git ne sont pas des reproches mais des jugements personnels.
Simple
Quand vous recherchez “git vs mercurial” sur votre voteur de recherche préféré, vous tomberez sans doute sur cet argument principal. Mercurial est plus simple que Git. C’est vrai, Mercurial possède moins d’options et moins de commandes qui sont aussi plus concises. Cela ne veut pas dire que Mercurial est moins puissant. Vous verrez pourquoi plus loin.
Prenons par exemple la commande commit, voici la différence entre Git et Mercurial :
$ hg help commit | wc -l
59
$ git help commit | wc -l
320
Certes la documentation est détaillée, mais Git possède un nombre
élevé d’options ce qui permet à git commit
de faire
beaucoup trop de choses à mon sens.
KISS
Mercurial et Git sont différents dans leurs commandes. Mercurial respecte le principe KISS bien plus fortement que Git.
Prenons par exemple la commande git checkout
. Cette
dernière permet de :
- Créer une branche avec
git checkout -b
, - Réinitialiser des fichiers
git checkout -- files...
, - Changer de branche
git checkout mabranche
.
Dans Mercurial, il s’agit de 3 commandes différentes,
hg branch
, hg revert
et
hg update
.
Homogène
Mercurial est presque entièrement écrit en Python. Certaines parties sont écrites en C pour des raisons de performances, mais il est possible d’installer Mercurial en python-pur. Notez que c’est peu recommandé toutefois. Git, en contrepartie est codé en C, perl, shell et dans certains cas awk et ruby.
J’apprécie aussi le fait que chaque commande est implémentée de la même manière, avec un système de décorateur en python. Ce qui signifie que chaque documentation ou erreur de commande renvoie le même message.
Exemple avec des options qui n’existent pas entre Git et Mercurial :
$ git commit -x
error: unknown switch `x'
usage: git commit [<options>] [--] <pathspec>...
$ git send-email -x
No patch files specified!
git send-email [options] <file | directory | rev-list options >
$ git log -x
fatal: unrecognized argument: -x
En contrepartie, Mercurial :
$ hg commit -x
hg commit: option -x not recognized
hg commit [OPTION]... [FILE]...
$ hg branch -x
hg branch: option -x not recognized
hg branch [-fC] [NAME]
Note : une partie des commande a été tronqué pour des raisons esthétiques.
Intégration
Dans Mercurial, toutes les commandes sont intégrées avec aucune autre
dépendance. Mon exemple préféré est hg serve
et
git instaweb
.
La commande hg serve
créé un petit serveur web
directement dans le dépôt permettant une lecture seule par défaut du
dépôt depuis un navigateur. Ceci utilise python uniquement sans aucune
dépendance. En contrepartie, la commande git
instaweb utilise divers outils externe et est d’une complexité hors
norme.
Phases
Un système de phases est présent dans Mercurial, ce qui vous empêche par défaut de faire n’importe quoi dans votre projet.
Il y a 3 phases dans Mercurial : secret < draft < public.
Par défaut, quand vous faites un commit, votre révision est en draft.
Cela signifie que vous pouvez encore la modifier ou la déplacer. Celle
ci deviendra publique si vous la transmettez sur un autre dépôt. Une
fois publique, il est interdit de modifier ces révisions et la plupart
des commandes vous le diront. Il est néanmoins possible de forcer un
changement de phase quand on sait ce qu’on fait. La dernière phase
secret permet de ne pas transmettre par erreur une révision qu’on
voudrait garder localement encore. Celle ci s’obtient en utilisant
hg commit -s
.
Utilisable en script
Rejoignant un peu la section KISS au dessus, les sorties de commandes de Mercurial sont toujours simples. Cela permet aux développeurs de scripts de pouvoir s’intercaler convenablement sur les sorties de commandes.
Exemple entre hg status
et git status
:
Pour les deux cas, je pars d’un dépôt vide et je rajoute juste un README.md.
$ git status
On branch master
No commits yet
Changes to be committed:
(use "git rm --cached <file>..." to unstage)
new file: README.md
Avec Mercurial :
$ hg status
A README.md
Les commandes hg in
et hg out
Deux commandes de Mercurial qui sont vraiment pratique, elles permettent de voir si des révisions vont être soumises ou récupérées.
Portable
Mercurial est 100% portable. C’est un des objectifs principaux du projet. Il fonctionne exactement de la même manière sur Mac, Linux et Windows. Par ailleurs, les développeurs de TortoiseHg ont aussi fait le bon choix d’utiliser Qt pour l’interface graphique. Ainsi, d’un système à l’autre, vous avez exactement la même interface, solide intégrée et native.
En contrepartie, Git sur Windows est particulièrement de moins bonne qualité et certaines des commandes ne fonctionnent pas très bien sur cmd.exe. Bon je vous l’accorde, quelle idée d’utiliser la ligne de commande Windows.
Templates
Les templates forment un moyen de personnaliser la sortie des
commandes. Cela se passe avec le paramètre -T
lorsque la
commande est supportée.
Exemple avec hg log
, je souhaite afficher uniquement les
révisions :
$ hg log -T '{node}\n'
6dcaa3331044d0b52280b58ae32fac138b9fdbc8
2e1ea792ddfd0b8cbea856f2550deb9cc56ca038
72034ab78d2aae8a1007b85169d7ae298f8be2d4
Je souhaite afficher les révisions courtes et la première ligne de leur description :
hg log -T '{rev}: {desc|firstline}\n'
65: Marker: style & fix
64: Docs: add custom definition list syntax
63: Marker: add custom definition list, closes #899 @1h
62: Marker: new style
61: Marker: update usage
Les templates permettent aussi de rajouter des filtres sur le contenu
comme vous pouvez le voir sur le format {desc|firstline}
où
firstline est une fonction qui s’applique sur la description.
Je vous laisse le soin de regarder hg help templates
pour plus amples informations.
Revsets
De la même manière des templates, il est possible de sélectionner des révisions parmi un ensemble de requêtes. Cela permet entre autre d’exporter, supprimer, déplacer un certain type de révisions.
Pour ce faire, certaines commandes permettent de sélectionner des
ensembles de révisions avec la plupart du temps un paramètre
-r
.
Par exemple, il est tout à fait possible de lister toutes les révisions encore considérées draft.
$ hg log -r 'draft()'
changeset: 66:2b7ecb2b2152
user: David Demelier <markand@malikania.fr>
date: Tue Aug 21 21:40:34 2018 +0200
summary: ajout de foo.md
changeset: 67:f97f50da2a23
bookmark: @
tag: tip
user: David Demelier <markand@malikania.fr>
date: Tue Aug 21 21:40:40 2018 +0200
summary: ajout de bar.md