Vous êtes ici : Accueil / 2009 / Mai / Un tutorial en français sur l'utilisation de Mercurial

Un tutorial en français sur l'utilisation de Mercurial

écrit le 08/04/2010 Par jerome
Ce document explique les concepts théoriques de Mercurial, puis montre les commandes de base (pour le développeur pressé qui connaît déjà CVS ou SVN par exemple), avant de détailler les commandes avancées (branches, tags...). Tout ce que vous avez jamais eu envie de savoir sur Mercurial sans oser le demander !

Concepts de base

Dans CVS et SVN, l'unité de base d'information est la revision ou version, correspondant à l'état précis d'un fichier (pour CVS) ou de l'ensemble des fichiers du dépôt (pour SVN). Dans Mercurial, l'unité de base est le changeset , littéralement « ensemble de changements ». Pour simplifier, on peut dire que CVS et SVN stockent les versions successives des fichiers (et calculent ensuite les diff à la volée), tandis que Mercurial stocke les différences entre les versions (et recalcule les fichiers à la volée). Ça n'est pas toujours vrai techniquement, mais c'est une bonne approximation !

Pour bien se représenter un dépôt Mercurial, il faut l'imaginer comme un graphe orienté acyclique (pour éviter d'employer les grands mots : un arbre dans lequel certaines branches peuvent se rejoindre) :

  •   les nœuds du graphe sont les revisions, c'est-à-dire un ensemble de fichiers dans un état bien défini
  •   les arêtes du graphe sont les changesets, qui définissent comment passer d'un nœud (état) à l'autre ;
  •   les nœuds d'où ne part aucune arête (les feuilles de l'arbre, autrement dit) sont appelés heads : c'est (généralement) là que se fait le développement ;
  •   il y a un premier nœuds particulier : la revision 0, qui correspond à un dépôt vide (c'est l'état du dépôt lorsqu'on le crée) ;
  •   il y a un autre nœud particulier : le plus récent, surnommé aussi tip (pointe en anglais).

 

 Lorsqu'on souhaite identifier une revision, on peut le faire de plusieurs façons différentes :

  • À l'aide de son hash SHA1 (qui est une chaîne hexadécimale, par exemple 3f43056373ce), ou d'une fraction de ce hash. Ce hash identifie de manière unique une version donnée des fichiers, à la manière d'un code barre. Il est permanent : du début à la fin du projet, la version 3f43056373ce désignera toujours la même chose. En revanche, il n'est pas très commode à manipuler (taper hg update -r 3f43056373 ce n'est pas très agréable).
  • À l'aide de son numéro, le local revision number. C'est un numéro qui commence à zéro (pour la revision initiale, vide) et qui va en s'incrémentant, comme le numéro de revision SVN. Attention : comme son nom l'indique, ce numéro de version est local. En effet, si votre dépôt contient les versions 1, 2, 3 correspondant à des commits faits lundi, mercredi et vendredi, si vous fusionnez avec le dépôt de quelqu'un d'autre, qui a fait un commit le jeudi, ce commit deviendra la version 3, et votre commit de vendredi (qui était n°3) deviendra la version 4. L'avantage de ces numéros de version est qu'ils sont facile à simples à saisir, par rapport aux hash décrits au point précédent. On peut ainsi taper hg diff -r 14:17 au lieu de  hg diff -r 3f43056373ce:4e80ca12880f
  • À l'aide d'un tag. Un tag est une sorte de marqueur, ou d'étiquette, que l'on peut attacher à une version donnée. Par exemple, si on décide qu'une version donnée devient la version 1.4.3 du projet, on peut associer à cette revision le tag 1.4.3 ; et on pourra ensuite avantageusement taper  hg update -r 1.4.3 au lieu de hg update -r 3f43056373ce par exemple. La revision la plus récente a automatiquement le tag tip.

 

Un système distribué

CVS et SVN sont des systèmes centralisés. Il y a un dépôt qui sert de référence. On dispose bien sûr d'une copie locale de ses fichiers, qu'on peut modifier à loisir ; mais à chaque fois que l'on souhaite comparer sa copie locale avec celle du dépôt, ou revenir à une ancienne version, il est nécessaire d'être connecté à ce dépôt central.


Mercurial, tout comme GIT et BZR par exemple, est comparable à un système peer-to-peer. On dispose dans sa copie locale de toutes les versions précédentes du projet (ce qui permet d'effectuer des comparaisons et des retours en arrière sans se connecter au dépôt à chaque fois). On peut aussi créer des nouvelles versions (faire un commit) sans être connecté à ce dépôt. En fait, chaque développeur dispose de son propre dépôt, en local sur son ordinateur. L'échange avec les autres développeurs peut passer par le biais d'un dépôt central, ou bien par plusieurs dépôts.

Voici quelques exemples d'organisations possibles :

  •  Il existe un dépôt central qui sert de référence et d'archive pour le projet, ainsi que plusieurs dépôts intermédiaires pour chaque équipe de développeurs ou pour chaque sous-projet. Chaque développeur travaille sur son propre dépôt (sur son ordinateur), et envoie régulièrement ses changesets sur le dépôt de l'équipe. Une personne (ou une petite équipe) est ensuite responsable de consolider et faire remonter ces changesets sur le dépôt central, une fois qu'un certain niveau de maturité et de stabilité est atteint, par exemple. C'est un système similaire qui est adopté pour le développement du noyau Linux (qui utilise GIT) : des « chefs de file » coordonnent les efforts dans le domaine des drivers, de la gestion mémoire, etc., et agissent comme un filtre vis-à-vis du dépôt central géré par Linus Torvalds.
  •  Il existe plusieurs dépôts indépendants. Par exemple, plusieurs sociétés travaillent sur un projet Open Source commun. Pour éviter des problématiques techniques (disponibilité et sauvegarde du dépôt central), voire politiques (pourquoi une des organisations devrait-elle avoir un rôle prépondérant vis-à-vis des autres et héberger le dépôt central?), chacune peut disposer de son propre dépôt. Les développeurs sont ensuite libres d'aller chercher des versions sur l'un ou l'autre, et une version identifiée par un hash sera la même sur les deux dépôts.

Les commandes essentielles

 Créer un dépôt :

 mkdir toto ; cd toto ; hg init

 Récupérer un dépôt existant :

hg clone http://adresse.du.depot/chemin/

 Ajouter un fichier au dépôt, renommer un fichier, effacer un fichier :

hg add toto.py ; hg mv toto.py titi.py ; hg rm titi.py

 Enregistrer ses modifications dans son dépôt local :

hg commit -m "modification du zbouib" toto.py

Si on ne spécifie pas de message de commit, un éditeur se lance ; si on ne spécifie pas de fichier à enregistrer, tous les fichiers modifiés sont pris en compte.

 Envoyer ses modifications au dépôt distant :

hg push

 Récupérer les modifications distantes (cela ne modifie pas votre copie de travail) :

hg pull

 Voir les 4 dernières modifications (les 4 derniers commits) :

hg log -r tip:-4

 Intégrer dans sa copie de travail les nouvelles modifications :

hg update

 Marquer une version précise :

hg tag 1.0.4

 Marquer une branche (c'est comme un tag, sauf que cela reste sur les versions suivantes) :

hg branch sans_support_opengl

 Lister les branches, les tags :

hg branches

et

 hg tags

 Commencer à travailer sur une autre branche, une autre version ... :

hg update -r nom_branche_ou_nom_tag_ou_hash_de_version

Créer un dépôt indépendant

On peut créer un dépôt indépendant et le servir (sur un réseau local ou sur Internet, si on est sur une machine accessible de l'extérieur) sans avoir besoin d'avoir les droits root ou d'installer des logiciels supplémentaires. En effet, Mercurial contient un petit serveur intégré. Il suffit de créer un fichier de configuration minimal, pour indiquer à ce petit serveur qu'on peut l'utiliser en lecture-écriture (avec l'option allow_push), car par défaut, il est en lecture seule ; et qu'on autorise les connexions non cryptées (avec push_ssl).

# mkdir oeufdepaques
# cd oeufdepaques
oeufdepaques# hg init
oeufdepaques# cat >.hg/hgrc <<EOF
> [web]
> allow_push = *
> push_ssl = false
> EOF
oeufdepaques# hg serve


Bien sûr, il est possible (et même recommandé) de configurer Apache pour servir ses dépôts Mercurial ; mais il y a déjà des tonnes de documentation sur le net, qui expliquent comment faire cela, donc nous laisserons cette tâche en exercice au lecteur.

Commencer à travailler avec la repository

Une fois que le serveur de l'étape précédente est lancé, on peut aller dans un autre répertoire, et récupérer le dépôt (qui est vide pour l'instant) :

# hg clone http://localhost:8000/ lapin
no changes found
updating working directory
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
# cd lapin

On peut aussi créer un dépôt vide, puis le configurer à la main pour dire que par défaut, les opérations push et pull devront « parler » avec un certain dépôt distant. La suite de commandes ci-dessous est strictement équivalente à l'autre ci-dessus :

# mkdir lapin
# cd lapin
lapin# hg init
lapin# cat >.hg/hgrc <<EOF
> [paths]
> default = http://localhost:8000/
> EOF
lapin# hg pull
pulling from http://localhost:8000/
no changes found

Et si l'on souhaite juste faire un pull ponctuel à partir d'un dépôt, on peut le spécifier en argument :

# mkdir lapin
# cd lapin
lapin# hg init
lapin# hg pull http://localhost:8000/
pulling from http://localhost:8000/
no changes found

Commencer à travailler sur son dépôt local

On va créer quelques fichiers et les ajouter au dépôt. Les commandes sont ici totalement identiques à celles que l'on utilise déjà pour CVS ou SVN :

lapin# touch chocolat.py lait.py
lapin# hg add chocolat.py lait.py "ajout des premiers fichiers du projet"

lapin# echo 'from cacao import beans' >> chocolat.py
lapin# hg commit -m "correction d'un import manquant"

Si on souhaite voir les dernières modifications faites sur le dépôt, rien de plus simple. La commande hg log affiche toutes les modifications (sur un projet assez avancé, elle sera donc peu pratique à utiliser telle quelle, car elle risque d'afficher quelques milliers de lignes ; on utilisera alors, par exemple  hg log -r tip:-4 pour indiquer qu'on veut voir le log depuis le tip - la dernière version en date - et remonter 4 versions en arrière) :

lapin# hg log
 changeset:   1:86e652ec797a
 tag:         tip
 user:        skaya@enix.org
 date:        Mon Apr 13 12:17:57 2009 +0200
 summary:     correction d'un import manquant

 changeset:   0:803f0bf542b9
 user:        skaya@enix.org
 date:        Mon Apr 13 12:17:02 2009 +0200
 summary:     ajout des premiers fichiers du projet

Si l'on souhaite revenir à une ancienne version, on fait comme avec SVN : on fait un update, mais en spécifiant une version spécifique en argument :

 lapin# hg update -r 01 files updated
0 files merged, 0 files removed, 0 files unresolved

Et pour revenir à la version la plus récente, rien de plus simple :

 lapin# hg update # ou hg update -r tip1 files updated
 0 files merged, 0 files removed, 0 files unresolved

Manipuler les « tags »

Les tags permettent d'identifier de manière lisible et stable une version donnée. Lisible, car il est plus facile de taper  hg update -r release_1.0.4 que hg update -r 86e652ec797a

Et stable, car les numéros locaux de version peuvent changer d'un dépôt à l'autre, ou bien si on fait un pull qui ajoute des versions intermédiaires. En réalité, les tags sont stockés dans un fichier .hgtags , lui aussi contrôlé par Mercurial (comme n'importe quel fichier du dépôt). Il n'y a donc aucune « magie » là-dedans. Notons que la commande hg tag fait implicitement un commit, et crée donc une nouvelle version :

lapin# hg tag avant_split_chocolat
lapin# cat .hgtags
86e652ec797a672d413b556d2ccec28f3cddb96d avant_split_chocolat

Faisons quelques autres modifications :

lapin# mkdir chocolat
lapin# touch chocolat/noir.py chocolat/blanc.py
lapin# hg add chocolat
lapin# hg rm chocolat.py
lapin# hg commit -m "séparation de chocolat.py en deux sous-modules"

Et regardons ensuite le journal des modifications :

lapin# hg log
changeset:   3:d92c1aae7b39
tag:         tip
user:        skaya@enix.org
date:        Mon Apr 13 12:22:53 2009 +0200
summary:     séparation de chocolat.py en deux sous-modules

changeset:   2:46e88f07aaef
user:        skaya@enix.org
date:        Mon Apr 13 12:20:36 2009 +0200
summary:     Added tag avant_split_chocolat for changeset 86e652ec797a

changeset:   1:86e652ec797a
tag:         avant_split_chocolat
user:        skaya@enix.org
date:        Mon Apr 13 12:17:57 2009 +0200
summary:     correction d'un import manquant

changeset:   0:803f0bf542b9
user:        skaya@enix.org
date:        Mon Apr 13 12:17:02 2009 +0200
summary:     ajout des premiers fichiers du projet

Comme promis, on peut utiliser le tag comme argument d'un hg update (et on pourra l'utiliser pour toutes les commandes prenant un argument -r et attendant un numéro de version comme argument) :

lapin# hg update -r avant_split_chocolat
1 files updated, 0 files merged, 3 files removed, 0 files unresolved

Gérer les « heads »

Comment Mercurial gère-t-il la division du développement en plusieurs branches séparées ? Contrairement à SVN qui ne propose aucun mécanisme particulier pour cela (c'est à chacun de se discipliner et de créer des sous-répertoires, d'où la disposition typique d'un dépôt Subversion avec les répertoires trunk, branches et tags), Mercurial dispose du concept de head . Mettons-le à l'épreuve :

lapin# echo 'from farm import cow, goat' >> lait.py
lapin# hg commit -m "imports manquants dans lait.py"
created new head

Mercurial nous indique que ce 'commit' a crée une nouvelle « tête » - on a donc crée un « split » du code, ou une « branche », appelons-cela comme on veut. Par défaut, cette branche n'a pas de nom particulier ; mais nous verrons plus tard qu'on peut associer un nom à une branche afin de s'y retrouver plus facilement.

Une commande bien pratique et très simple permet de voir toutes les  heads . Bien sûr, sur un projet très complexe, il peut y avoir plusieurs dizaines de  heads , et la commande n'est alors plus si pratique que ça.

lapin# hg heads
changeset:   4:a8f6f55f6674
tag:         tip
parent:      1:86e652ec797a
user:        skaya@enix.org
date:        Mon Apr 13 12:25:43 2009 +0200
summary:     imports manquants dans lait.py

changeset:   3:d92c1aae7b39
user:        skaya@enix.org
date:        Mon Apr 13 12:22:53 2009 +0200
summary:     séparation de chocolat.py en deux sous-modules

Vous vous sentez perdu ? Vous avez besoin d'un plan ? Pas de problème, Mercurial a pensé à tout. Essayez donc : lapin# hg view

Échanger des données avec d'autres dépôts

On peut commencer à envoyer nos modifications au dépôt qui a été créé au début de la démo. La commande push sert à cela, et elle a le bon goût de nous indiquer laconiquement qu'on a créé une nouvelle head  sur le dépôt distant.

lapin# hg push
pushing to http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 5 changesets with 7 changes to 5 files (+1 heads)

 Un autre développeur peut commencer à travailler avec notre code, sur son dépôt local :

# hg clone http://localhost:8000/ carotte
 requesting all changes
 adding changesets
 adding manifests
 adding file changes
 added 5 changesets with 7 changes to 5 files (+1 heads)
 updating working directory
 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
 # cd carotte
 carotte# hg heads
 changeset:   4:a8f6f55f6674
 tag:         tip
 parent:      1:86e652ec797a
 user:        skaya@enix.org
 date:        Mon Apr 13 12:25:43 2009 +0200
 summary:     imports manquants dans lait.py

changeset:   3:d92c1aae7b39
 user:        skaya@enix.org
 date:        Mon Apr 13 12:22:53 2009 +0200
 summary:     séparation de chocolat.py en deux sous-modules

Lorsqu'on fait un update qui fait passer d'une branche à l'autre, Mercurial nous demande si l'on souhaite fusionner (merge) ces deux branches, ou si l'on souhaite simplement passer d'une branche à l'autre (pour travailler sur une autre portion du code, par exemple) : 

carotte# hg update -r 3
abort: crosses branches (use 'hg merge' or 'hg update -C')

carotte# hg update -r 3 --clean # le "--clean", ou "-C", veut dire "oublie mes modifs locales"
4 files updated, 0 files merged, 1 files removed, 0 files unresolved

Gérer différentes branches de développement

Cela se passe le plus simplement du monde : on utilise la commande hg branch. Une branch  dans Mercurial, c'est un peu comme un tag , mais qui n'identifie pas une version précise, mais plutôt toutes les versions à partir d'une version donnée. Si on a en tête l'image du dépôt sous forme d'arbre (ou plus précisément, de graphe acyclique orienté, comme évoqué en introduction), la notion de branche est assez intuitive. Notons que la création d'une branche, contrairement à celle d'un tag, ne fait pas de commit implicite :

carotte# hg branch bichoco
marked working directory as branch bichoco
carotte# hg commit -m "création de la branche bichoco avec le sous-rep chocolat"
carotte# hg update -r 4 # on revient à la branche où on n'a pas séparé les fichiers
carotte# hg branch monochoco
marked working directory as branch monochoco
carotte# hg commit -m "création de la branche avec un seul module chocolat.py"
carotte# hg branches
monochoco                      6:c62a89e0b18e
bichoco                        5:f69e772d76b7
default                        4:a8f6f55f6674 (inactive)

Une branche est « inactive » si elle ne contient pas de head . Cela se tient : a priori, quand on fait un commit, c'est toujours sur une head ; si une branche ne contient pas de head , on ne peut pas y faire de commit, la branche est donc inactive. Bien sûr, on peut à tout instant créer une head  n'importe où (et donc rendre une branche active).

 On peut passer d'une branche à l'autre avec hg update, avec exactement la même syntaxe que pour les tags et les numéros de version :

 carotte# hg update -r bichoco
 4 files updated, 0 files merged, 1 files removed, 0 files unresolved
 carotte# touch chocolat/noisettes.py
 carotte# hg add chocolat/noisettes.py
 carotte# hg commit -m "ajout d'une variété de chocolat"

 carotte# hg update -r monochoco
 2 files updated, 0 files merged, 4 files removed, 0 files unresolved
 carotte# echo 'cow.debug()' >> lait.py 
 carotte# hg commit -m "activation du debug sur les vaches"

Tiens, et si on a oublié de faire un commit, et qu'on essaie de changer de branche ? Pas de panique, Mercurial ne nous laisse pas faire, et nous demande si on souhaite abandonner les modifications locales :

 carotte# echo 'goat.debug()' >> lait.py 
 carotte# hg update -r bichoco
 abort: crosses named branches (use 'hg update -C' to discard changes)
 carotte# hg update -r bichoco --clean # tant pis pour les chèvres
 5 files updated, 0 files merged, 1 files removed, 0 files unresolved

Fusionner des branches

Parfois (souvent même), on a deux branches qui évoluent indépendamment (par exemple, la branche « avec le nouveau driver vidéo » et la branche « avec le nouveau driver son »), et à un point donné, on souhaite les réunir, les fusionner.

La commande à utiliser est hg merge -r 57 si on souhaite par exemple fusionner la version en cours avec la version 57. Bien entendu, comme pour toutes les autres commandes acceptant un numéro de version, on peut spécifier un numéro local, un tag, un hash, ou un nom de branche.

Si on est dans une head  et qu'il y a exactement une autre head  dans la repository, on peut taper hg merge sans argument.
 
Petit exemple - on commence par poser un tag avant de diviser le code en deux branches :

 carotte# hg tag avant_separation_lait
 carotte# mkdir lait
 carotte# touch lait/ecreme.py lait/entier.py
 carotte# hg add lait
 adding lait/ecreme.py
 adding lait/entier.py
 carotte# hg rm lait.py
 carotte# hg commit -m "séparation du module lait.py en sous-modules"

Puis on revient à la version sur laquelle on avait posé le tag, et on fait d'autres modifications, afin de créer la nouvelle branche :

carotte# hg update -r avant_separation_lait
2 files updated, 0 files merged, 2 files removed, 0 files unresolved

 carotte# touch cloche.py
 carotte# hg add cloche.py 
 carotte# hg commit -m "Pacques avec des cloches, c'est mieux"
 created new head
 carotte# echo 'from modules import *' >> cloche.py 
 carotte# hg commit -m "imports pour le fichier cloche"

Arrivé à ce stade, on a trois heads  :

carotte# hg heads
changeset:   12:d085363e36ad
branch:      bichoco
tag:         tip
user:        skaya@enix.org
date:        Tue Apr 14 11:26:31 2009 +0200
summary:     imports pour le fichier cloche

changeset:   10:ca090e171d78
branch:      bichoco
user:        skaya@enix.org
date:        Tue Apr 14 08:48:15 2009 +0200
summary:     séparation du module lait.py en sous-modules
 
changeset:   8:c81783a7b4c2
branch:      monochoco
parent:      6:c62a89e0b18e
user:        skaya@enix.org
date:        Tue Apr 14 08:37:19 2009 +0200
summary:     activation du debug sur les vaches

On revient sur une de ces  heads  pour faire une modification :

carotte# hg update -r 10 -C
carotte# touch lait/demiecreme.py
carotte# hg add lait/demiecreme.py
carotte# hg commit -m "ajout du lait demi-écrémé"
carotte# hg heads
changeset:   13:546203b18b0a
branch:      bichoco
tag:         tip
parent:      10:ca090e171d78
user:        skaya@enix.org
date:        Tue Apr 14 11:37:39 2009 +0200
summary:     ajout du lait demi-écrémé

changeset:   12:d085363e36ad
branch:      bichoco
user:        skaya@enix.org
date:        Tue Apr 14 11:26:31 2009 +0200
summary:     imports pour le fichier cloche

changeset:   8:c81783a7b4c2
branch:      monochoco
parent:      6:c62a89e0b18e
user:        skaya@enix.org
date:        Tue Apr 14 08:37:19 2009 +0200
summary:     activation du debug sur les vaches

 Et on demande explicitement de fusionner la head courante avec la version locale numéro 12 :

carotte# hg merge -r 12
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
carotte# hg diff
diff -r 546203b18b0a cloche.py
--- /dev/null    Thu Jan 01 00:00:00 1970 +0000
+++ b/cloche.py    Tue Apr 14 13:48:53 2009 +0200
@@ -0,0 +1,1 @@
+from modules import *
carotte# hg commit -m "fusion de la branche lait.py/module lait séparé"
carotte# hg heads
changeset:   14:845a003202fd
branch:      bichoco
tag:         tip
parent:      13:546203b18b0a
parent:      12:d085363e36ad
user:        skaya@enix.org
date:        Tue Apr 14 13:50:52 2009 +0200
summary:     fusion de la branche lait.py/module lait séparé

changeset:   8:c81783a7b4c2
branch:      monochoco
parent:      6:c62a89e0b18e
user:        skaya@enix.org
date:        Tue Apr 14 08:37:19 2009 +0200
summary:     activation du debug sur les vaches

Puis, on envoie nos modifications vers le dépôt, pour les autres développeurs :

carotte# hg push
pushing to http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 10 changesets with 8 changes to 7 files

Gestion des conflits

Que se passe-t-il si un autre développeur fait des modifications sur les mêmes fichiers que nous ? Au moment de faire un push (pour envoyer ses données sur le dépôt), il va recevoir un message lui disant « push creates new remote heads! », c'est-à-dire que quelqu'un d'autre a fait un commit au même endroit que lui. Il y a alors deux options : forcer le push (et créer une ou plusieurs heads  sur le dépôt distant), ou bien faire d'abord un pull et tenter un éventuel merge avant de refaire le push. L'exemple qui suit montre le second cas (la manière « propre ») :

lapin# echo 'lang=en' > eastereggs.conf
lapin# hg add eastereggs.conf
lapin# hg commit -m "ajout du fichier de config"
lapin# hg push
pushing to http://localhost:8000/
searching for changes
abort: push creates new remote heads!
(did you forget to merge? use push -f to force)
lapin# hg pull 
pulling from http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 10 changesets with 8 changes to 7 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
lapin# hg heads
changeset:   15:845a003202fd
branch:      bichoco
tag:         tip
parent:      14:546203b18b0a
parent:      13:d085363e36ad
user:        skaya@enix.org
date:        Tue Apr 14 13:50:52 2009 +0200
summary:     fusion de la branche lait.py/module lait séparé

changeset:   9:c81783a7b4c2
branch:      monochoco
parent:      7:c62a89e0b18e
user:        skaya@enix.org
date:        Tue Apr 14 08:37:19 2009 +0200
summary:     activation du debug sur les vaches

changeset:   5:9fc05d4f2214
 user:        skaya@enix.org
 date:        Fri Apr 17 21:18:13 2009 +0200
 summary:     ajout du fichier de config

lapin# hg merge -r 9
lapin# 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
lapin# hg diff
diff -r 9fc05d4f2214 lait.py
--- a/lait.py    Fri Apr 17 21:18:13 2009 +0200
+++ b/lait.py    Fri Apr 17 21:20:56 2009 +0200
@@ -1,1 +1,2 @@
from farm import cow, goat
+cow.debug()
lapin# hg commit -m "merge de la conf dans la branche monochoco"
lapin# hg parents -r tip
changeset:   5:9fc05d4f2214
user:        skaya@enix.org
date:        Fri Apr 17 21:18:13 2009 +0200
summary:     ajout du fichier de config
 
changeset:   9:c81783a7b4c2
branch:      monochoco
parent:      7:c62a89e0b18e
user:        skaya@enix.org
date:        Tue Apr 14 08:37:19 2009 +0200
summary:     activation du debug sur les vaches

lapin# hg update -r 5
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
lapin# hg merge -r 15
local changed lait.py which remote deleted
use (c)hanged version or (d)elete? d
8 files updated, 0 files merged, 2 files removed, 0 files unresolved
(branch merge, don't forget to commit)
lapin# hg commit -m "merge de la conf dans la branche bichoco"
lapin# hg push
pushing to http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 3 changesets with 1 changes to 1 files

Mais on peut aussi forcer le push, cela ne pose pas de problème particulier (à part que cela crée de nouvelles  heads , ce qui n'est pas forcément ce qu'on veut!) :

carotte# echo 'lang=fr' > eastereggs.conf
carotte# hg add eastereggs.conf
carotte# hg commit -m "ajout du fichier de conf en français"
carotte# hg push
pushing to http://localhost:8000/
searching for changes
abort: push creates new remote heads!
(did you forget to merge? use push -f to force)
carotte# hg push -f
pushing to http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files (+1 heads)
carotte# hg pull
pulling from http://localhost:8000/
searching for changes
adding changesets
adding manifests
adding file changes
added 3 changesets with 1 changes to 1 files (+1 heads)
(run 'hg heads' to see heads, 'hg merge' to merge)
carotte# hg heads
changeset:   18:3f43056373ce
tag:         tip
parent:      16:9fc05d4f2214
parent:      14:845a003202fd
user:        skaya@enix.org
date:        Fri Apr 17 21:28:23 2009 +0200
summary:     merge de la conf dans la branche bichoco

changeset:   17:925a9da09222
parent:      16:9fc05d4f2214
parent:      8:c81783a7b4c2
user:        skaya@enix.org
date:        Fri Apr 17 21:22:12 2009 +020
summary:     merge de la conf dans la branche monochoco

changeset:   15:cf32f157731c
branch:      bichoco
user:        skaya@enix.org
date:        Fri Apr 17 21:30:16 2009 +0200
summary:     ajout du fichier de conf en français

carotte# hg merge -r 17

Je suis perdu !
Il vous faut un plan ? Essayez : hg view :-)

hg view

Conclusion


 Nous avons vu comment :

  •   créer un dépôt ;
  •  travailler en local sur ce dépôt ;
  •   échanger des données avec un dépôt distant ;
  •   placer des tags ;
  •   créer des branches ;
  •   passer d'une branche à l'autre ;
  •   fusionner des branches (et des *heads* en général).

 
 Quelques commandes simples n'ont pas été détaillées, mais leur utilisation est très intuitive :

  •   hg cat -r 57 toto.py qui permet d'afficher le fichier toto.py tel qu'il était dans la version numéro 57 ; 

  •   hg grep -r 4 import qui permet de rechercher la chaîne "import" dans tous les fichiers de la version numéro 4 ; 

  •   hg diff -r release_1.0:422 qui permet d'afficher les différences entre la version ayant le tag « release_1.0 » et la version numéro 422.


 Il reste quelques concepts qui n'ont pas été abordés par ce document, tels que (liste non exhaustive) :

  •   la commande bissect, qui permet de trouver rapidement la version exacte (et donc la modification précise du code) qui a introduit un bug ;
  •   les commandes permettant de manipuler des bundles - il s'agit de fichiers contenant des groupes de changesets, autrement dit une version sérialisée d'un dépôt ou d'un ensemble de changesets (format adapté à la diffusion via un service tel que S3, par exemple) ;
  •   les commandes incoming et outgoint, que l'on peut lancer avant un pull ou un push respectivement, et affichent les changesets qui vont être transférés.

 

Actions sur le document