ka.da

Aller au contenu | Aller au menu | Aller à la recherche

Mot-clé - Mercurial

Fil des billets - Fil des commentaires

dimanche, juin 6 2010

Rapide guide pratique pour l'utilisation des branches Mercurial


L'article de Steve Losh A Guide to Branching in Mercurial permet de se faire une bonne idée du fonctionnement et des possibilités offertes par Mercurial pour gérer des "branches" (afin d'avoir des lignes de développement distinctes).

L'article Mercurial Workflows: Stable & Default quant à lui présente plus précisément la solution "branches nommées" (named branches).

Mais il manque d'exemples pratiques à mon goût, et comme je devais l'expliquer en détail à des amis, voici ma tentative de guide pratique appliqué à la théorie expliquée dans l'article sus-cité.

On commence par initialiser un projet, à créer quelques fichiers et à les committer séparément

$ hg init projet
$ cat > a
hello a
^D
$ hg add a
$ hg commit -m 'ajout a'
$ hg glog --style compact
@  0[tip]   a82264640870   2010-06-05 23:39 +0200   eric
     a

$ cat > b
hello b
^D
$ hg add b
$ hg commit -m 'ajout b'
$ hg glog --style compact
@  1[tip]   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


On a pour l'instant une seule branche

$ hg branches
default                        1:39bf03acf954


On en crée une sous le nom stable. Elle sera utilisée pour gérer les corrections de bugs de la version stable, tandis que le développement courant aura lieu dans la branche default

$ hg branch stable
marked working directory as branch stable
$ hg commit -m 'stable branch'
$ hg branches
stable                         2:97c9284f569c
default                        1:39bf03acf954 (inactive)


Pour l'instant, l'historique des révisions reste linéaire

$ hg glog --style compact
@  2[tip]   97c9284f569c   2010-06-05 23:42 +0200   eric
|    stable branch
|
o  1   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


On met à jour le dépôt pour utiliser la branche default et on modifie à nouveau des fichiers

$ hg update default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg branches
stable                         2:97c9284f569c
default                        1:39bf03acf954 (inactive)
$ cat >> a
bye a
^D
$ cat a
hello a
bye a


Quand on committe notre code, une nouvelle "tête" (head) est créée et l'historique n'est alors plus linéaire, ce qui montre que la branche default diverge de la branche stable, celle-ci étant un sous-ensemble de la première

$ hg commit -m 'bye a'
created new head
$ hg heads --style compact
3[tip]:1   bc970099e4f8   2010-06-05 23:53 +0200   eric
  bye a

2   97c9284f569c   2010-06-05 23:42 +0200   eric
  stable branch
$ hg glog --style compact
@  3[tip]:1   bc970099e4f8   2010-06-05 23:53 +0200   eric
|    bye a
|
| o  2   97c9284f569c   2010-06-05 23:42 +0200   eric
|/     stable branch
|
o  1   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


Faisons de nouvelles modifications dans la branche de développement principal

$ cat > c
hello c
^D
$ hg add c
$ hg commit -m 'ajout c'
$ hg glog --style compact
@  4[tip]   290b943b61d5   2010-06-05 23:54 +0200   eric
|    ajout c
|
o  3:1   bc970099e4f8   2010-06-05 23:53 +0200   eric
|    bye a
|
| o  2   97c9284f569c   2010-06-05 23:42 +0200   eric
|/     stable branch
|
o  1   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


Et retournons dans la branche stable pour corriger quelques bugs

$ hg update stable
1 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ cat >> a
fix a
$ hg commit -m 'fix a'
hg glog --style compact
@  5[tip]:2   26c5f5e23509   2010-06-05 23:55 +0200   eric
|    fix a
|
| o  4   290b943b61d5   2010-06-05 23:54 +0200   eric
| |    ajout c
| |
| o  3:1   bc970099e4f8   2010-06-05 23:53 +0200   eric
| |    bye a
| |
o |  2   97c9284f569c   2010-06-05 23:42 +0200   eric
|/     stable branch
|
o  1   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


Maintenant il faut bien évidemment que ces corrections de bugs se retrouvent également dans la branche de dev default

$ hg update default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge 26c5f5e23509
merging a
0 files updated, 1 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit -m 'merge with 26c5f5e23509 (stable branch)'
$ hg glog --style compact
@  6[tip]:4,5   fb323a167af1   2010-06-05 23:57 +0200   eric
|\     merge with 26c5f5e23509 (stable branch)
| |
| o  5:2   26c5f5e23509   2010-06-05 23:55 +0200   eric
| |   fix a
| |
o |  4   290b943b61d5   2010-06-05 23:54 +0200   eric
| |    ajout c
| |
o |  3:1   bc970099e4f8   2010-06-05 23:53 +0200   eric
| |    bye a
| |
| o  2   97c9284f569c   2010-06-05 23:42 +0200   eric
|/     stable branch
|
o  1   39bf03acf954   2010-06-05 23:41 +0200   eric
|    ajout b
|
o  0   a82264640870   2010-06-05 23:39 +0200   eric
     ajout a


On voit bien que le fichier a contient le code venant des deux branches (même si ça se joue au moment du merge)

$ cat a
hello a
fix a
bye a


Quand vous voulez remplacer la branche stable il suffit de merger avec default

$ hg update stable
$ hg merge 290b943b61d5
$ hg commit -m 'merge with 290b943b61d5'


Pour fermer définitivement la branche, utiliser l'option --close-branch à hg commit.

et voili...

note : l'article a été écrit rapidement donc n'hésitez pas à signaler toute erreur

mercredi, juin 3 2009

Mercurial : éditer l'historique d'un dépôt (les changesets) avec les MQ

J’ai toujours[1] cru qu’on ne pouvait éditer l’historique des ‘changesets’ de Mercurial, mais en fait si ! Et c’est grâce à ce billet sur le blog de Jesper Noehr (un des gars derrière bitbucket) que j’ai découvert qu’en fait c’est tout à fait possible.

En utilisant les MQ (mercurial queues) dont je vous ai déjà parlé, il est donc tout à fait possible de rééditer des modifications déjà enregistrées (committées) dans votre dépôt Mercurial.

Bien évidemment, ce genre de manipulations n’est possible que si vous contrôlez votre dépôt et ses éventuels clones. Dès l’instant où celui-ci a pu être cloné, vous avez perdu la maîtrise de votre code et les modifications sur lesquelles vous voulez revenir sont déjà parties.

Nous sommes dans un dépôt test avec 3 changesets

$ hg log
changeset:   2:6a2d12a15cda
tag:         tip
summary:     modifications de a et b

changeset:   1:ca5faf3b4493
summary:     ajout de b

changeset:   0:66545c7be018
summary:     ajout de a

et nous souhaitons revenir sur les changesets 1 et 2.

Nous initialisons d’abord un dépôt de MQ si ce n’est pas déjà fait

$ hg qinit -c

[2]

Puis nous importons les changesets que nous voulons modifier

$ hg qimport -r 2:1

Si on regarde maintenant le log

changeset:   2:6a2d12a15cda
tag:         qtip
tag:         2.diff
tag:         tip
summary:     modification de a et b

changeset:   1:ca5faf3b4493
tag:         1.diff
tag:         qbase
summary:     ajout de b

changeset:   0:66545c7be018
tag:         qparent
summary:     ajout de a

on retrouve bien nos 3 différents changesets sauf que les 2 derniers sont différents : ce sont maintenant des patchs sous forme MQ que nous pouvons alors manipuler de façon classique[3]

On peut donc dépiler tous les patchs pour revenir dans l’état qu’on voulait avant les changesets 1 et 2

$ hg qpop -a
Patch queue now empty
$ hg log
changeset:   0:66545c7be018
tag:         tip
summary:     ajout de a

On peut alors à coup de hg qpush/hg qpop empiler/dépiler nos patchs afin de les modifier, les réorganiser ou ajouter des changesets, et donc revenir sur l’historique de notre dépôt.

J’ai découvert qu’en fait cette information est également disponible sur le site de Mercurial, voyez http://www.selenic.com/mercurial/wi…

Notes

[1] “toujours” est peut-être un trop grand mot, ça ne fait pas non plus si longtemps que ça que je connais Mercurial ;-)…

[2] tant qu’à faire nous ajoutons -c pour avoir un dépôt MQ ‘versionnable’

[3] je vous renvoie vers les chapitre 12 et 13 du hgbook pour plus d’infos

vendredi, décembre 12 2008

Mercurial : partager votre dépôt de patches MQ en même temps que votre dépôt principal

Travaillant actuellement sur un projet de développement en mode collaboratif, nous utilisons Mercurial pour gérer nos sources, et je me suis mis à utiliser intensément les MQ (Mercurial Queues) pour gérer mes propres modifications.

Je ne vais pas rentrer dans les détails de ce que sont les MQ, juste vous dire que c’est un système permettant de gérer une série de patchs “flottants”, un peu comme des commits mais que vous pouvez dépiler et empiler pour les modifier suivant vos besoins, tout en suivant le développement principal.
Je vous renvoie vers la documentation officielle et le chapitre qui y est consacré dans le livre (à lire et relire pour comprendre le principe).

Jusque là en travaillant de mon côté avec des MQ, je pouvais tranquillement poursuivre plusieurs développements en parallèle en local, tout en suivant le développement sur la branche principale. Quand un patch était ok, je l’appliquais sur le dépôt principal et tout allait bien.
Le problème se pose maintenant parce que je veux, tout en maintenant une série de patches, pouvoir les partager afin de montrer l’avancée de mon travail. (tout en continuant à pouvoir les empiler/dépiler bien évidemment)
C’est possible mais pas très pratique : ça demande de réinitialiser le dépôt côté serveur et les numéros de changesets changent, sans parler de l’obligation de passer par un dépôt local tiers.

Je me suis donc mis à chercher de la doc sur le partage de patches MQ et suis tombé sur ce très intéressant article intitulé Using Mercurial Queues and bitbucket.org[1] et, ne voulant pas utiliser bitbucket pour stocker mon dépôt[2], me suis mis en tête de faire quelque chose d’équivalent sur mon propre hébergement.

Peu de doc existe donc voici la mienne…

Sur le serveur

on commence par initialiser un dépôt qu’on va appeler test

$ hg init /chemin/vers/test

puis on y initialise un dépôt de MQ (qui l’on retrouvera dans .hg/patches)

$ cd /chemin/vers/test
$ hg qinit -c

on doit ensuite créer un fichier hgrc afin de spécifier les autorisations de chacun des deux dépôts : /chemin/vers/test/.hg/hgrc et /chemin/vers/test/.hg/patches/.hg/hgrc : je ne rentre pas dans les détails et vous renvoie vers mon article dédié au partage de dépôts Mercurial si vous en avez besoin.

Il faut également ajouter ces deux dépôts dans la configuration hgweb(dir).cgi

[paths]
test  =  /chemin/vers/test/
test-mq = /chemin/vers/test/.hg/patches

Si vous allez sur l’url de votre site vous devriez alors voir quelque chose comme ça Capture-Mercurial_repositories_index_-_Iceweasel.png

Sur le client

Clone

on clone le dépôt en précisant qu’on veut également le dépôt de MQ grâce à la commande dédiée qclone

$ hg qclone http://hg.domain.tld/test

Push

quand on veut pusher nos modifications sur le dépôt en y incluant notre dépôt de patches, il faut

  • d’abord dépiler tous les patches
$ hg qpop -a
  • ensuite pusher le dépôt principal
$ hg push https://hguser@hg.domain.tld/test
  • puis le dépôt MQ
$ hg push https://hguser@hg.domain.tld/test-mq

Pull

pour mettre à jour notre dépôt local avec les modifications disponibles sur le serveur, il faut procéder de la même façon que pour le push avec la commande pull : dépiler les patchs, mettre à jour chacun des deux dépôts.

Voilà, je crois que je n’ai rien oublié, n’hésitez pas à me le dire si c’est le cas.

Notes

[1] je reparlerais peut-être d’ailleurs à une autre occasion de bitbucket mais pour faire simple c’est une sorte de github à la sauce Mercurial

[2] principalement parce que pour l’instant le développement est fermé, quand il s’ouvrira bitbucket pourra être une solution intéressante

mardi, avril 22 2008

Mercurial : faire des modifications distantes et avoir les fichiers mis à jour sur le serveur

Aujourd'hui, j'ai découvert quelque chose d'étrange en utilisant Mercurial.

J'ai donc un dépôt privé accessible via https (cf ce post), je le clone, je fais des modifications, je committe, puis je push sur le serveur

$ hg clone https://code.veiras.info/private_repo
$ vi...
$ hg commit -m "nouvelles modifs"
$ hg push
http authorization required
realm: code.veiras.info Mercurial repository
user: X
password: X
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 3 changes to 3 files

Jusque là tout va bien, c'est la façon normale de travailler et j'ai toujours fait comme ça. Sauf qu'aujourd'hui, j'étais également connecté sur mon serveur en ssh, je vais donc dans mon dépôt, un hg tip me dit bien que je viens de faire un commit, mais par contre quand je veux regarder mes fichiers... mes modifications n'y sont pas et là, je tombe des nues : qu'ai-je donc fait mal ? Encore une histoire de permissions sur les fichiers ?

<mode panique>ÇA VEUT DIRE QUE TOUT CE QUE J'AI COMMITTÉ DEPUIS TOUT CE TEMPS EST PERDU ???!!!</mode panique>

vite fait, je saute sur mon client IRC préféré[1] et rebondit sur #mercurial (sur freenode) où l'on me rassure (?) en me disant que tout est normal.

Pour résumer :

  • si je veux avoir les modifs également sur les fichiers en local sur le serveur, il faut que je fasse un hg update sur le serveur;
  • si je veux automatiser cet update, il faut utiliser un 'hook' : plus d'informations sur le site officiel ou sur le guide non officiel;
  • si on utilise pas sur le serveur le dépôt, on peut même effacer tout les fichiers à l'exception du répertoire .hg/, celui-ci contenant justement tout l'historique du dépôt.
  • si on veut effacer ces fichiers, un rm * pouvant poser des problèmes plus tard, il est préférable d'utiliser hg update null qui permet de revenir à la révision 0
  • si jamais on a à nouveau besoin de ces fichiers sur le serveur, un hg update fera l'affaire.

Notes

[1] j'en profite pour signaler l'existence de mibbit.com très pratique quand on est coincé derrière un proxy et qu'on a besoin d'aide...

mercredi, janvier 30 2008

Mercurial : partage de dépôts différents en http et https + push par https

J’ai commencé à regarder du côté des SCM[1] (marre de la gestion CPOLD ;-) il y a quelque temps déjà, et m’était tout d’abord arrêté sur Subversion [2] étant novice en la matière. Il s’est vite révélé peu adapté à ma pratique : “développement” sur plusieurs machines pas toujours online, et pas de serveur dédié toujours en ligne pour stocker mes dépôts. Depuis peu, ce dernier problème s’est réglé (merci Gandi Hébergement[3]) mais pour autant, j’ai abandonné Subversion pour Mercurial, un gestionnaire de code source distribué.

Je ne vais pas entrer ici dans les détails sur les caractéristiques d’un gestionnaire de code source distribué, ses avantages, ou même sur une présentation détaillée sur Mercurial et son mode de fonctionnement (je vous laisse visiter le site officiel pour cela). Je vais uniquement présenter des détails sur la configuration que j’ai mise en place afin de parvenir à partager aisément des dépôts différents via http et https, ainsi que comment faire pour autoriser la mise à jour de ceux-ci via https.


présentation des dépôts Mercurial sur le web


Imaginons que vos dépôts soient stockés dans /mercurial et que vous vouliez pouvoir donner un accès en lecture sur le web, à l’adresse http://hg.domain.tld. Nous allons configurer Apache et Mercurial pour ce faire.

Tout d’abord, nous allons créer un emplacement pour les fichiers web et le script CGI en Python pour Mercurial. Prenons /var/www/domain.tld/hg. Créons à cet endroit un répertoire hgweb dans lequel nous allons placer le script hgwebdir.cgi que vous pouvez trouver sur votre système (sous Debian /usr/share/doc/mercurial/examples/hgwebdir.cgi) ou sur le site de Mercurial. Éditez ce fichier pour avoir à la fin :

def make_web_app():
    return hgwebdir("/etc/mercurial/hgweb.config")

Nous allons ensuite créer le fichier /etc/mercurial/hgweb.config avec un contenu comme suit :

[paths]
depot1  =  /mercurial/depot1
depot2  =  /mercurial/depot2

On peut également utiliser la directive [collections] pour partager une hiérarchie de dépôts mais nous partons du principe que l’on veut contrôler précisément ce que l’on partage.

À partir de là, il nous reste à configurer Apache. Créez un fichier /etc/apache2/sites-available/hg.domain.tld afin de déclarez votre VirtualHost. Voici en exemple mon fichier

NameVirtualHost *:80

<VirtualHost *:80>
    ServerAdmin webmaster@hg.domain.tld

    ServerName hg.domain.tld  

    DocumentRoot /var/www/domain.tld/hg

    <Directory /var/www/domain.tld/hg/>
        Options FollowSymLinks +ExecCGI
        AddHandler cgi-script .cgi
        DirectoryIndex hgweb/hgwebdir.cgi
        AllowOverride None

        RewriteEngine on
        RewriteBase /hgweb
        RewriteRule ^$ hgwebdir.cgi  [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule (.*) hgwebdir.cgi/$1  [QSA,L]
    </Directory>

    LogLevel warn
    ErrorLog /var/log/apache2/hg.domain.tld-error.log
.   CustomLog /var/log/apache2/hg.domain.tld-access.log combined
    
    ServerSignature Off
</VirtualHost>

Notez ici les règles de réécriture qui permettent de faire disparaître hgwebdir.cgi de vos URL. C’est ce qui m’a pris le plus de temps à trouver avant de tomber sur cette doc.

Activez votre nouveau “site” ainsi que les modules Apache dont vous aurez besoin

# a2ensite hg.domain.tld
# a2enmod mod_python
# a2enmod rewrite
# /etc/init.d/apache2 restart

Vous pouvez maintenant aller voir http://hg.domain.tld et parcourir vos dépôts Mercurial depot1 et depot2


partager des dépôts différents par https


Tout ça, c’est très bien, mais on aimerait également pouvoir avoir accès à certains dépôts que l’on ne veut pas donner en lecture à tout internet : des dépôts privés en somme. Nous allons donc partager ceux-ci sur un site sécurisé avec authentification.

Nous allons donc retourner dans notre répertoire /var/www/domain.tld/hg/hgweb, copier hgwebdir.cgi en hgwebdirssl.cgi et éditez ce fichier pour avoir :

def make_web_app():
    return hgwebdir("/etc/mercurial/hgwebssl.config")

Créons le fichier /etc/mercurial/hgwebssl.config avec :

[paths]
depot1  =  /mercurial/depot1
depot2  =  /mercurial/depot2
depot_prive3 = /mercurial/depot3
depot_prive4 = /mercurial/depot4

Et retournons éditer /etc/apache2/sites-available/hg.domain.tld pour y ajouter :

# en haut du fichier
NameVirtualHost *:443

# à la fin du fichier
<VirtualHost *:443>
    ServerAdmin webmaster@hg.domain.tld

    ServerName hg.domain.tld

    DocumentRoot /var/www/domain.tld/hg

    SSLEngine on
    SSLCertificateFile /etc/apache2/ssl/hg.domain.tld.pem
    SSLCertificateKeyFile /etc/apache2/ssl/hg.domain.tld.key

    <Directory /var/www/domain.tld/hg/>
        Options FollowSymLinks +ExecCGI
        AddHandler cgi-script .cgi
        DirectoryIndex hgweb/hgwebdirssl.cgi
        AllowOverride None

        RewriteEngine on
        RewriteBase /hgweb
        RewriteRule ^$ hgwebdirssl.cgi  [L]
        RewriteCond %{REQUEST_FILENAME} !-f
        RewriteRule (.*) hgwebdirssl.cgi/$1  [QSA,L]

        AuthUserFile /etc/mercurial/hgweb.htpasswd
        AuthGroupFile /dev/null
        AuthName "hg.domain.tld Mercurial repository"
        AuthType Basic
#       <LimitExcept GET OPTIONS>
                Require valid-user
#       </LimitExcept>
    </Directory>

    ErrorLog /var/log/apache2/hg.domain.tld-error.log

    LogLevel warn

    CustomLog /var/log/apache2/hg.domain.tld-access.log combined
    ServerSignature Off

</VirtualHost>

On retrouve ici les directives rewrite que nous avons utilisé dans la première partie, à la différence qu’elles pointent vers le CGI spécifique à notre configuration SSL, et quelques directives spécifiques justement à https/SSL. Bien évidemment, il vous faudra créer un fichier de mots de passe (nommé ici hgweb.htpasswd) avec :

# htpasswd -c /etc/mercurial/hgweb.htpasswd hguser

pour autoriser l’utilisateur hguser.

Notez les directives <LimitExcept GET OPTIONS> qui, si elles sont décommentées, permettent à tout le monde de visualiser les dépôts tout en demandant une authentification pour interagir via les commandes de Mercurial (clone, pull, push…).

Rechargez la configuration d’Apache et regardez la différence entre http://hg.domain.tld et https://hg.domain.tld


autoriser la mise à jour des dépôts via https


Pour autoriser le push via https, une fois le travail ci-dessus effectué, il suffit d’éditer la configuration des dépôts en modifiant le fichier .hg/hgrc de chaque projet. Éditez-le ou créez-le et insérez les lignes suivantes :

[web]
allow_push = hguser


utilisation


Voilà c’est fait, vous pouvez maintenant interagir très simplement avec vos dépôts Mercurial. Pour cloner un dépôt public

$ hg clone http://hg.domain.tld/depot1

Pour cloner un dépôt privé

$ hg clone https://hguser@hg.domain.tld/depot_prive3

Pour mettre à jour (push) ce même dépôt

$ hg push https://hguser@hg.domain.tld/depot_prive3

J’ajouterais que le plus dur est de gérer finement les droits d’accès aux divers fichiers nécessaires au bon fonctionnement de cette configuration. Pour faire simple, comme d’habitude, laissez le minimum de droits sur les fichiers de configuration (appartenance à l’utilisateur www-data et lecture pour lui), et pour les dépôts j’ai choisi la solution un groupe devel pour mon utilisateur principal ainsi que www-data et les droits pour ce groupe.

mise à jour : il semble nécessaire (depuis les dernières mises à jour de Mercurial ?) d’ajouter une ligne baseurl = dans la section [web] des fichiers .hg/hgrc afin de cacher les hgweb(dir).cgi dans les url.

Notes

[1] définition en français et en anglais

[2] cf cet article

[3] je sais que je n’ai pas parlé de cette nouvelle offre très intéressante de Gandi le registrar bien connu (pour sa qualité de service, son support et son engagement) alors allez voir le bar de gandi