Introduction à la gestion de version avec Mercurial

http://www.selenic.com/hg-logo/logo-droplets-200.png
Auteurs:Alain Leufroy, Pierre-Yves David.

Table des Matières

Un DVCS Kézako ?

Un DVCS, est un "Distributed Version Control System" !

La gestion de versions consiste à maintenir l'ensemble des versions d'un ou plusieurs fichiers […] Cette activité étant fastidieuse et relativement complexe, un appui logiciel est presque indispensable.

—Wikipedia

C'est donc l'outil qui permet de gérer intelligemment les sauvegardes de vos travaux. C'est le compagnon indispensable du programmeur, scientifique, auteur, etc…


Mercurial est un outil :

  • Simple
  • Sûr
  • Décentralisé
  • Multiplateforme (même sur plan9 !)
  • Activement maintenu
  • Rapide
  • Puissant
  • Extensible

Travailler en local

Installation

Vous aurez évidemment besoin de Mercurial. (disponible sur http://mercurial.selenic.com/)

Pour visualiser l'historique, nous conseillons Hgview:

linux:
paquet hgview
windows:
http://www.logilab.org/file/104947
Mac:
Demander au Gentil Présentateur

Configurer

Prenons le temps de configurer un minimum les choses en éditant le fichier de configuration utilisateur de mercurial.

C'est un simple fichier INI. Vous le trouverez à ~/.hgrc sur systèmes UNIX et plan9, et à %USERPROFILE%/Mercurial.ini (par default C:\Documents and Settings\XXX\Mercurial.ini) sur Windows

A minima, renseignez votre nom :

$ cat >> $HGRCPATH << EOF
> [ui]
> username = test <testeur@mondomaine.org>
> EOF

Nous utilisons pour ce tutoriel l'interface officielle en ligne de commandes : hg [options globales] COMMANDE [options spécifiques] [ARGS]

Il existe d'autres interfaces (TortoiseHg, mode Emacs, EclipseHg, Hgview,...).

Vous pouvez obtenir de l'aide et/ou accéder à la documentation avec la commande help.

$ hg help showconfig

Astuces

  • hg help permet de retrouver une commande
  • hg help log permet d'avoir des détails sur la commande log et de retrouver les options spécifiques
  • hg help -v log permet d'avoir aussi les options globales
  • hg help config permet d'avoir l'aide au sujet de la configuration de Mercurial

Exercices

Regardez l'aide sur la "config" et ajoutez un raccourci quisuisje pour "showconfig ui.username" (section alias). Puism observez la sortie de $ hg quisuisje

$ cat >> $HGRCPATH << EOF
> [alias]
> quisuisje=showconfig ui.username
> EOF

Premiers pas

La première étape consiste à créer un dépôt vierge de changeset (ou revision) :

$ hg init pyconfr
$ cd pyconfr

Créons un script python :

$ cat >> babar.py << EOF
> # -*- coding: utf-8 -*-
> #! /usr/bin/env python
>
> """Mon beau petit script"""
>
> print "Mon script python est cool !"
>
> EOF

Il faut explicitement demander à Mercurial de surveiller le fichier babar.py. Nous le mettons alors sous contrôle de version puis juste après nous figeons son état dans une révision (ou changeset)

$ hg add babar.py
$ hg commit --message 'version initiale'

Pensez à regarder l'aide des commandes pour plus d'informations (hg help add et hg help commit).

--message omis, Mercurial démarre votre éditeur de texte car la description est obligatoire. On mettra donc hg commit pour renseigner une description plus complète.

Astuces

Les "révisions" sont des états figés et sauvegardés de vos fichiers : "Commitez" rapidement, et souvent !

Nous avons une révision datée, revendiquée, et commentée :

$ hg log
changeset:   0:ac45076e2510
tag:         tip
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     version initiale


$ hg -v log
changeset:   0:ac45076e2510
tag:         tip
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
files:       babar.py
description:
version initiale

Astuces

Vous pouvez utiliser des logiciels graphiques comme HgView qui pourront rester ouverts en permanence pendant que vous travaillez sur votre dépôt.

Exercices

Créez un dossier avec deux fichiers à l'intérieur. Ajoutez-les à votre dépôt et faites une nouvelle révision. Puis observez la sortie de hg log -G:

$ mkdir dossier
$ echo 'le contenu de fichier 1' > dossier/fichier_1
$ echo 'le contenu de fichier 2' > dossier/fichier_2
$ hg add dossier
adding dossier/fichier_1
adding dossier/fichier_2
$ hg commit --message "ajout d'un dossier"
$ hg log -G
@  changeset:   1:996158b51bfe
|  tag:         tip
|  user:        test
|  date:        Thu Jan 01 00:00:00 1970 +0000
|  summary:     ajout d'un dossier
|
o  changeset:   0:ac45076e2510
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     version initiale

Travaillons un peu

Nous allons maintenant modifier notre fichier pour qu'il affiche le contenu d'un fichier passé en argument :

$ cat > babar.py << EOF
> # -*- coding: utf-8 -*-
> #! /usr/bin/env python
>
> """Mon beau petit script"""
>
> import sys
>
> print sys.argv[-1]
>
> EOF

Vous pouvez avoir différentes informations sur l'état actuel de votre dépôt (dir state) avec :

$ hg summary
parent: 1:996158b51bfe tip
 ajout d'un dossier
branch: default
commit: 1 modified
update: (current)

$ hg status
M babar.py

$ hg diff -g babar.py
diff --git a/babar.py b/babar.py
--- a/babar.py
+++ b/babar.py
@@ -3,5 +3,7 @@

 """Mon beau petit script"""

-print "Mon script python est cool !"
+import sys

+print sys.argv[-1]
+

Astuces

hg summary donne une très bonne vue générale de l'état de votre dépôt. Pensez à l'utiliser avant toute opération sur votre dépôt. Il vous dira si vous avez oublié un hg add ou si des modifications parasites sont présentes.

Si vous avez plus de fichiers modifiés que vous ne l'espériez, utilisez hg status pour les trouver.

Pensez à relire vos modifications avec hg diff. Les meilleures modifications sont les plus simples et sont faciles à relire !

On fait une nouvelle révision :

$ hg ci --message "Permet d'afficher le contenu du fichier en argument"

$ hg log
changeset:   2:339b3e5f3521
tag:         tip
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     Permet d'afficher le contenu du fichier en argument

changeset:   1:996158b51bfe
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     ajout d'un dossier

changeset:   0:ac45076e2510
user:        test
date:        Thu Jan 01 00:00:00 1970 +0000
summary:     version initiale

Astuces

Il existe des alias spécifiques pour les commandes les plus courantes permettant de réduire le nombre de caratères à taper.

Vous pouvez même ne taper que le début du nom de la commande. Mercurial doit touefois disposer de suffisamment de caractères pour retrouver la commande sans ambigüité.

Astuces

Vous pouvez activer l'extension color pour ajouter des couleurs à la plupart des commandes. Ajoutez les lignes suivantes à votre hgrc

| [extensions]
| color=

Voyager dans le temps est possible !

Vous voici devant votre premier défi : remonter dans le temps !

Le premier avantage d'un gestionnaire de contrôle de versions est de pouvoir revenir dans un état figé antérieur.

$ tree
.
|-- babar.py
`-- dossier
    |-- fichier_1
    `-- fichier_2

1 directory, 3 files
$ hg update ac45076e2510
1 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ ls
babar.py

$ cat babar.py
# -*- coding: utf-8 -*-
#! /usr/bin/env python

"""Mon beau petit script"""

print "Mon script python est cool !"

$ hg log --template "{rev}) {desc}\n"
2) Permet d'afficher le contenu du fichier en argument
1) ajout d'un dossier
0) version initiale

Astuces

La commande log qui vous permet d'observer le contenu de votre dépôt (pas celui des fichiers), comporte de nombreuses options pour filtrer et personnaliser sa sortie. Vous pourrez prendre un peu de temps pour lire hg -v help log et hg help template.

On peut remarquer que l'on a oublié le texte de la licence dans la version initiale :-/ Ajoutons-la !

$ hg summary
parent: 0:ac45076e2510
 version initiale
branch: default
commit: (clean)
update: 2 new changesets (update)

$ cat > babar.py << EOF
> # -*- coding: utf-8 -*-
> #! /usr/bin/env python
> # License: WTFPL v. 2
>
> """Mon beau petit script"""
>
> print "Mon script python est cool !"
>
> EOF

$ hg summary
parent: 0:ac45076e2510
 version initiale
branch: default
commit: 1 modified (new branch head)
update: 2 new changesets (update)

$ hg diff -g
diff --git a/babar.py b/babar.py
--- a/babar.py
+++ b/babar.py
@@ -1,5 +1,6 @@
 # -*- coding: utf-8 -*-
 #! /usr/bin/env python
+# License: WTFPL v. 2

 """Mon beau petit script"""


$ hg ci -m '[license] oOPps: Ajoute la license au script python'
created new head

Mais qu'est-ce donc que cette nouvelle tête ?

$ hg log --graph --template="\t{rev}) {desc}\n"
@     3) [license] oOPps: Ajoute la license au script python
|
| o   2) Permet d'afficher le contenu du fichier en argument
| |
| o   1) ajout d'un dossier
|/
o     0) version initiale

La modification (ajout de la licence) à été versionnée alors que nous étions sur la révision 0) version initiale. Le lien de parenté est conservé. Nous avons alors l'arbre "généalogique" des révisions. Celui-ci comporte 2 branches et deux têtes.

Astuces

L'option --graph de la commande log est très souvent utilisée. Vous pouvez créer un alias glog dans votre configuration Mercurial

| [aliases]
| glog = log -G

Notre fichier contient :

$ cat babar.py
# -*- coding: utf-8 -*-
#! /usr/bin/env python
# License: WTFPL v. 2

"""Mon beau petit script"""

print "Mon script python est cool !"

Mais nous souhaiterions aussi "ajouter un dossier" et "permettre d'afficher le contenu du fichier en argument". Nous allons donc rassembler les deux branches [1] :

[1]Cette situation est plutôt artificielle. Elle sert surtout de prétexte pour introduire le concept de branche.
$ hg merge
merging babar.py
2 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

$ hg ci -m 'Fusion !'

$ hg log -v -G
@    changeset:   4:3b60711b69f9
|\   tag:         tip
| |  parent:      3:831e8464b77f
| |  parent:      2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  files:       babar.py
| |  description:
| |  Fusion !
| |
| |
| o  changeset:   3:831e8464b77f
| |  parent:      0:ac45076e2510
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  files:       babar.py
| |  description:
| |  [license] oOPps: Ajoute la license au script python
| |
| |
o |  changeset:   2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  files:       babar.py
| |  description:
| |  Permet d'afficher le contenu du fichier en argument
| |
| |
o |  changeset:   1:996158b51bfe
|/   user:        test
|    date:        Thu Jan 01 00:00:00 1970 +0000
|    files:       dossier/fichier_1 dossier/fichier_2
|    description:
|    ajout d'un dossier
|
|
o  changeset:   0:ac45076e2510
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
   files:       babar.py
   description:
   version initiale



$ hg summary
parent: 4:3b60711b69f9 tip
 Fusion !
branch: default
commit: (clean)
update: (current)

$ tree
.
|-- babar.py
`-- dossier
    |-- fichier_1
    `-- fichier_2

1 directory, 3 files

$ cat babar.py
# -*- coding: utf-8 -*-
#! /usr/bin/env python
# License: WTFPL v. 2

"""Mon beau petit script"""

import sys

print sys.argv[-1]

Identifier des révisions (revid)

L'arbre de révisions est à votre disposition, vous pouvez vous y balader, mais faisons-le à la manière de Tarzan.

Pour y parvenir, nous allons voir différentes façons d'identifier des révisions grâce aux différentes formes du revid. Pour avoir les identifiants de la révision courante :

$ hg identify
3b60711b69f9 tip

Les différentes façons d'identifier une révision sont :

numéro:[4], est local et dépend de l'historique de votre arbre ; nous aurions pu faire "Une autre variante" avant "Interactif maintenant".
identifiant:[12d134c4d432]: est un hash unique et sans ambigüité. Il est construit à partir du contenu des fichiers, des metadonnées et de la parenté.
tag:est un identifiant unique pour humain, c'est le pseudo de la révision.
bookmark:est une marque dans votre dépôt qui vous permet de suivre une thématique de modifications.

Les tags

Vous pouvez les déclarer avec la commande tag :

$ hg tag -r ac45076e2510 init

$ hg tag -r 3b60711b69f9 fusion

$ hg log -G
@  changeset:   6:2850220e4952
|  tag:         tip
|  user:        test
|  date:        Thu Jan 01 00:00:00 1970 +0000
|  summary:     Added tag fusion for changeset 3b60711b69f9
|
o  changeset:   5:4935bb98f72a
|  user:        test
|  date:        Thu Jan 01 00:00:00 1970 +0000
|  summary:     Added tag init for changeset ac45076e2510
|
o    changeset:   4:3b60711b69f9
|\   tag:         fusion
| |  parent:      3:831e8464b77f
| |  parent:      2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Fusion !
| |
| o  changeset:   3:831e8464b77f
| |  parent:      0:ac45076e2510
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     [license] oOPps: Ajoute la license au script python
| |
o |  changeset:   2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Permet d'afficher le contenu du fichier en argument
| |
o |  changeset:   1:996158b51bfe
|/   user:        test
|    date:        Thu Jan 01 00:00:00 1970 +0000
|    summary:     ajout d'un dossier
|
o  changeset:   0:ac45076e2510
   tag:         init
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     version initiale

On voit que les tags ont été déposés sur les révisions. Ils n'en bougeront plus (à moins de les enlever à la main). C'est une marque pérenne.

Astuces

Les tags sont souvent utilisés pour marquer une version particulière de votre projet.

S'il n'y a pas de restriction particulière pour les tags, il est largement préférable de n'utiliser que des caratères alphanumériques, le point . et le underscore _.

Vous pouvez alors utiliser les tags pour identifier des revisions :

$ hg up fusion
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg summary
parent: 4:3b60711b69f9 fusion
 Fusion !
branch: default
commit: (clean)
update: 2 new changesets (update)
$ hg up init
1 files updated, 0 files merged, 2 files removed, 0 files unresolved
$ python babar.py
Mon script python est cool !

Exercices

Remontez en haut de votre arbre d'historique. De là, ajouter un tag license à la révision qui intègre la licence. Déplacez-vous sur cette révision et ajouter le texte de votre licence et figez les modifications dans une nouvelle révision.

Revenez sur la révision 6:2850220e4952 puis "fusionnez" (merge) les modifications précédentes.

$ hg update
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg tag -r 831e8464b77f license
$ hg update license
1 files updated, 0 files merged, 3 files removed, 0 files unresolved
$ cat > babar.py << EOF
> # -*- coding: utf-8 -*-
> #! /usr/bin/env python
> # License: WTFPL v. 2
>
> # WTFPL v. 2: You just DO WHAT THE FUCK YOU WANT TO.
> """Mon beau petit script"""
>
> print "Mon script python est cool !"
>
> EOF
$ hg summary
parent: 3:831e8464b77f license
 [license] oOPps: Ajoute la license au script python
branch: default
commit: 1 modified (new branch head)
update: 6 new changesets (update)

$ hg ci -m 'ajoute le contenu de la license'
created new head

$ hg merge 53538fc8b983
merging babar.py
3 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

$ hg commit --message 'Fusion !'
$ hg log -G
@    changeset:   9:700db0dd081c
|\   tag:         tip
| |  parent:      8:9f31cfa47c9a
| |  parent:      7:53538fc8b983
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Fusion !
| |
| o  changeset:   8:9f31cfa47c9a
| |  parent:      3:831e8464b77f
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     ajoute le contenu de la license
| |
o |  changeset:   7:53538fc8b983
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag license for changeset 831e8464b77f
| |
o |  changeset:   6:2850220e4952
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag fusion for changeset 3b60711b69f9
| |
o |  changeset:   5:4935bb98f72a
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag init for changeset ac45076e2510
| |
o |  changeset:   4:3b60711b69f9
|\|  tag:         fusion
| |  parent:      3:831e8464b77f
| |  parent:      2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Fusion !
| |
| o  changeset:   3:831e8464b77f
| |  tag:         license
| |  parent:      0:ac45076e2510
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     [license] oOPps: Ajoute la license au script python
| |
o |  changeset:   2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Permet d'afficher le contenu du fichier en argument
| |
o |  changeset:   1:996158b51bfe
|/   user:        test
|    date:        Thu Jan 01 00:00:00 1970 +0000
|    summary:     ajout d'un dossier
|
o  changeset:   0:ac45076e2510
   tag:         init
   user:        test
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     version initiale

$ cd ..

Travailler avec mercurial

Vous pouvez aisément partager votre travail entre vos machines, avec des collaborateurs, voire même avec le monde entier...

Un des principes de base d'un DVCS, tient au fait que toutes les informations du dépôt sont disponibles localement. Il est donc possible d'effectuer l'ensemble des opérations sur le dépôt, depuis une machine tierce. Mercurial permet donc de travailler en mode "hors-ligne".

Dès lors, il est nécessaire de disposer de commandes de synchronisation avec d'autres dépôts, qui seront explicitement appelées.

Clone

La première opèration naturelle, quand on entre dans un projet, consiste à récupérer ses sources et leurs historiques. Cela permet de comprendre en partie les différents choix retenus (d'où l'importance des messages liés aux révisions).

On commencera donc par dupliquer le dépôt du projet avant de pouvoir y appliquer des modifications.

Il faut utiliser pour cela la commande hg clone source, où la source peut être :

  • un dépôt distant :
$ hg clone https://bitbucket.org/aleufroy/pyconfr
warning: bitbucket.org certificate with fingerprint 24:9c:45:8b:9c:aa:ba:55:4e:01:6d:58:ff:e4:28:7d:2a:14:ae:3b not verified (check hostfingerprints or web.cacerts config setting)
destination directory: pyconfr
requesting all changes
adding changesets
adding manifests
adding file changes
added 10 changesets with 11 changes to 4 files
updating to branch default
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd pyconfr
$ hg log -G
@    changeset:   9:700db0dd081c
|\   tag:         tip
| |  parent:      8:9f31cfa47c9a
| |  parent:      7:53538fc8b983
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Fusion !
| |
| o  changeset:   8:9f31cfa47c9a
| |  parent:      3:831e8464b77f
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     ajoute le contenu de la license
| |
o |  changeset:   7:53538fc8b983
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag license for changeset 831e8464b77f
| |
o |  changeset:   6:2850220e4952
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag fusion for changeset 3b60711b69f9
| |
o |  changeset:   5:4935bb98f72a
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Added tag init for changeset ac45076e2510
| |
o |  changeset:   4:3b60711b69f9
|\|  tag:         fusion
| |  parent:      3:831e8464b77f
| |  parent:      2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Fusion !
| |
| o  changeset:   3:831e8464b77f
| |  tag:         license
| |  parent:      0:ac45076e2510
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     [license] oOPps: Ajoute la license au script python
| |
o |  changeset:   2:339b3e5f3521
| |  user:        test
| |  date:        Thu Jan 01 00:00:00 1970 +0000
| |  summary:     Permet d'afficher le contenu du fichier en argument
| |
o |  changeset:   1:996158b51bfe
|/   user:        test
|    date:        Thu Jan 01 00:00:00 1970 +0000
|    summary:     ajout d'un dossier
|
o  changeset:   0:ac45076e2510

$ cd ..
  • un dépôt distant via une connexion sécurisée :
$ cd ..
$ hg clone ssh://hg@bitbucket.org/aleufroy/pyconfr2012
$ cd hgview
$ hg qv -l 5
$ cd ..
  • un dépôt local :
$ cd ..
$ hg clone /tmp/pyconfr pyconde
updating to branch default
4 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd pyconde
$ hg summary
parent: 9:700db0dd081c tip
branch: default
commit: (clean)
update: (current)

Astuces

Vous pouvez renseigner un identifiant de révision pour ne dupliquer que partiellement un dépôt. En général, dans ces cas on renseigne un numéro de version du projet, utilisé comme tag.

Push/Pull

Vous pouvez échanger votre historique avec les autres dépôts (aux permissions près). Il existe deux commandes pour la synchronisation : push et pull.

hg pull source:rapatrie l'historique d'un autre dépôt source en local.
hg push cible:transmet l'historique vers un autre dépôt cible

Astuces

Ici aussi vous pouvez renseigner l'identifiant pour limiter la partie de l'historique échangée.

Exercices

Dupliquez le dépôt pyconfr en pyconbe jusqu'à la révision license. Modifiez la licence puis figez une nouvelle révision.

Rapatriez le reste de l'historique de pyconfr et observez le contenu de votre dossier et celui de votre dépôt.

Fusionnez vos modifications aux changements rapatriés.

$ hg clone -r license https://bitbucket.org/aleufroy/pyconfr pyconbe
adding changesets
adding manifests
adding file changes
added 2 changesets with 2 changes to 1 files
updating to branch default
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd pyconbe

$ tree
.
`-- babar.py

0 directories, 1 file

$ hg log -G --template='{rev}:{node|short} | {desc}'
@  1:831e8464b77f | [license] oOPps: Ajoute la license au script python
|
o  0:ac45076e2510 | version initiale


$ cat > babar.py << EOF
> # -*- coding: utf-8 -*-
> #! /usr/bin/env python
> # WTFPL v. 2: You just DO WHAT THE FUCK YOU WANT TO.
>
> """Mon beau petit script"""
>
> print "Mon script python est cool !"
>
> EOF

$ hg ci -m 'met a jour la license'

$ hg pull
pulling from /tmp/pyconfr
searching for changes
adding changesets
adding manifests
adding file changes
added 8 changesets with 9 changes to 4 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)

$ tree
.
`-- babar.py

0 directories, 1 file

$ hg log -G --template='{rev}:{node|short} | {desc}'
o    10:700db0dd081c | Fusion !
|\
| o  9:9f31cfa47c9a | ajoute le contenu de la license
| |
o |  8:53538fc8b983 | Added tag license for changeset 831e8464b77f
| |
o |  7:2850220e4952 | Added tag fusion for changeset 3b60711b69f9
| |
o |  6:4935bb98f72a | Added tag init for changeset ac45076e2510
| |
o |  5:3b60711b69f9 | Fusion !
|\|
o |  4:339b3e5f3521 | Permet d'afficher le contenu du fichier en argument
| |
o |  3:996158b51bfe | ajout d'un dossier
| |
| | @  2:9205c8a8c3c7 | met a jour la license
| |/
| o  1:831e8464b77f | [license] oOPps: Ajoute la license au script python
|/
o  0:ac45076e2510 | version initiale

$ hg merge
merging babar.py
3 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)

Conflit de Fusion

Si deux branches modifient le même fichier, Mercurial a besoin de fusionner ces modifications lorsque ces branches sont fusionnées.

En cas de difficultés, Mercurial va faire appel à un outil externe. Si aucun outil n'est configuré des marqueurs de conflit seront utilisés (comme dans CVS).

La section merge-tools de l'aide explique comment configurer un tel outil. Vous pouvez aussi vous référer au fichier d'exemple fourni par Mercurial [2] .

[2]Attention, votre distribution linux l'a peut-être déjà activé par défaut.

Astuces

Mercurial implémente un certain nombre d'outils en interne, jetez y un œil :

  • merge
  • dump
  • prompt
  • fail
  • local
  • other

Exercices

Créez deux branches du projet réalisant des modifications conflictuelles au même endroit d'un même fichier. Puis lancez-vous dans une fusion avec hg merge.

Rechercher des erreurs

Il arrive que l'on récupère des révisions vérolées - car c'est connu, c'est toutjours de la faute des autres ...

Il est donc nécessaire de rechercher la révision problématique.

Astuces

Vous pouvez modifier de manière permanante la sortie de log en fixant un "template" personnalisé (hg help template):

$ cat >> $HGRCPATH << EOF
> [ui]
> logtemplate="{rev}:{node|short}> {desc}"
> EOF

Nous pouvons utilisez la commande log pour suivre l'évolution d'un fichier particulier:

$ hg log babar.py

Serve

La méthode la plus simple pour partager son propre dépôt avec d'autres personnes consiste à avoir une machine connectée à Internet et... la commande serve.

$ hg serve -p 41705 &
$ hgpid=$!
$ cd ..
$ hg clone http://localhost:41705 pyconuk
$ cd pyconuk
$ hg log -G --template="{rev}:{node|short} | {desc}"
$ kill -15 $hgpid

Exercices

Une fois vos serveurs Mercurial lancés, vous pouvez essayer de récupérer les dépôts de vos voisins.

Astuces

Il y a une version wsgi/cgi pour des utilisation en production: hg help hgweb.

Bundle

Il est possible de transporter des révisions d'un dépôt à l'autre sans connexion directe avec l'utilisattion des bundles. La commande bundle permet de générer les fichiers de synchronisation.

$ hg bundle pyconfr.tar.gz searching for changes 1 changesets found $ ls -lah pyconfr.tar.gz -rw-r--r-- 1 alain users 463 Sep 16 01:54 pyconfr.tar.gz

Patches

Les commandes export et import sont pratiques car elles permettent le partage de fichiers ".patch".

$ hg export --git -r license

L'option --git permet d'utiliser un format de patch plus complet que le vieux format UNIX. Activez dans la section diff de votre fichier de configuration le format git:

[diff]
git = true

On s'échangera donc des patches avec:

.. sourcecode:: ini
$ hg export --git -r license > license.patch $ sendmail license.patch $ readmail license.patch $ hg import --exact license.patch

L'option --exact applique le patch à l'endroit où il a été généré.

Astuces

L'extension patchbomb ajoute la command email simplifie grandement l'envoie de patch par mail. Il peut être un outil pratique pour permettre à des contributeurs externes de participer à un projet.

Autre fonctionnalités avancées

Revset: retrouver des révisions

Mercurial propose une langage de requête sur l'arbre de révisions: revset

Ce langage supporte un nombre de prédicats joints grâce à des opérateurs.

Les prédicats permettent de filter selon le nom de l'auteur author(str), la date(interval), le contenu de la description desc(str), disponible qu'en local outgoing(path), la parenté parants(set), etc ...

Les opérateurs permettent de joindre en combinant x and y, en rejetant x - y, en parcourant l'arbre des révisions x :: yy, en énumérant les numéros de révisions `` x : y``, en se déplacant sur le parent ^...

La liste complète des prédicats et des opérateurs est disponible dans l'aide hg help revset.

$ hg log -G --template='{rev}:{node|short} | {desc}'
@    10:700db0dd081c | Fusion !
|\
| o  9:9f31cfa47c9a | ajoute le contenu de la license
| |
o |  8:53538fc8b983 | Added tag license for changeset 831e8464b77f
| |
o |  7:2850220e4952 | Added tag fusion for changeset 3b60711b69f9
| |
o |  6:4935bb98f72a | Added tag init for changeset ac45076e2510
| |
o |  5:3b60711b69f9 | Fusion !
|\|
o |  4:339b3e5f3521 | Permet d'afficher le contenu du fichier en argument
| |
o |  3:996158b51bfe | ajout d'un dossier
| |
| | @  2:9205c8a8c3c7 | met a jour la license
| |/
| o  1:831e8464b77f | [license] oOPps: Ajoute la license au script python
|/
o  0:ac45076e2510 | version initiale

Il est possible d'utiliser un revset partout où une ou plusieurs révisions sont requises.

$ hg log -G --template='{rev}:{node|short} | {desc}' -r .
@  2:9205c8a8c3c7 | met a jour la license
|

$ hg log -G --template='{rev}:{node|short} | {desc}' -r .^
o  1:831e8464b77f | [license] oOPps: Ajoute la license au script python
|

$ hg log -G --template='{rev}:{node|short} | {desc}' -r 'desc("Fusion")'
@    10:700db0dd081c | Fusion !
|\
| o  7:2850220e4952 | Added tag fusion for changeset 3b60711b69f9
| |
| o    5:3b60711b69f9 | Fusion !
| |\
$ hg log -G --template='{rev}:{node|short} | {desc}' -r 'merge()::'

Il existe aussi un langage équivalent pour les requêtes sur les fichiers.