reseau social

Installation et utilisation de base de Subversion

Un article de ToutProgrammer.com.

Subversion est un système de contrôle des versions comme le célèbre CVS. Ce nouvel outil offre un grand nombre de fonctionnalités et d'innovations par rapport à son aîné. C'est ce que nous allons voir avec cet article.

Sommaire

[modifier] Introduction

Subversion est un système de contrôle des versions OpenSource distribué sous une licence compatible Apache/BSD. Cet outil en développement depuis plus de 3 ans propose un grand nombre de nouveautés par rapport à son aîné vieillissant qu'est CVS. Pour CVS, il est temps de passer la main comme a pu le faire RCS en son temps.

[modifier] Lexique et traductions

Comme tout lecteur n'a pas forcément la même expérience que l'autre avec les gestionnaires de versions, je vous propose un petit lexique des termes clés pour le sujet qui nous concerne.

  • ressource: tout document (fichier, répertoire, lien, ...) enregistré dans le référentiel,
  • référentiel: équivalent français pour repository. Certains préfèrent la traduction littérale "dépôt". Base de données conservant les différentes versions d'une ou plusieurs ressources,
  • copie de travail ou copie locale: partie ou ensemble d'un référentiel copié sur le poste de la personne chargée d'y faire des modifications,
  • commit: opération consistant à confirmer dans le référentiel les modifications apportées sur la copie de travail,
  • révision: toute modification effectuée sur une des ressources du référentiel produit une révision. Un numéro unique est donné à chacune de ces modifications: r0, r1, r2, r3, ... Un numéro de révision est aussi affecté au référentiel lui même,
  • tag/étiquette: marquage fait sur une révision afin d'y revenir plus tard. Le terme français ne me semble pas encore tout à fait accepté, j'utilise donc l'un ou l'autre.

[modifier] Fonctionnalités de Subversion

Subversion est un logiciel profitant des dernières innovations techniques. Voici une liste des fonctionnalités proposées par celui-ci:

  • Les fonctionnalités de CVS: La plupart des fonctionnalités de CVS sont intégrées à Subversion. Lorsque c'était possible, l'interface de Subversion a été calquée sur celle de CVS,
  • Les répertoires, renommages et les propriétés des fichiers sont versionnés: L'historique des versions ne se fait pas uniquement sur le contenu des fichiers ou leur existence comme le fait CVS. Cet historique se fait également sur les répertoires, les copies et les renommages. Les propriétés (méta-données) des fichiers ou répertoires sont versionnées,
  • Les commits sont véritablement atomiques: Lorsqu'un commit est fait sur un ensemble de ressources, il faut que la globalité du commit se termine correctement pour que celui-ci soit valide. Les numéros de révision ne sont plus sur les fichiers individuellement mais sur le commit lui-même,
  • Apache comme serveur réseau, WebDAV/DeltaV comme protocole: Subversion utilise le protocole WebDAV/DeltaV basé sur HTTP ainsi que le serveur Web Apache. Grâce à cela, Subversion tire avantage de ceux-ci pour l'authentification, l'autorisation d'accès basique, la compression à la volée ou le parcourt du référentiel. Pour les personnes désirant utiliser un tunnel ssh, il existe également une version standalone de Subversion,
  • Gestion des branches et des tags simplifiée: Les branches et les tags sont assimilés à des opérations de "copie". comme la création de copies, les branches et les tags ne sont que des références à des révisions dans le référentiel et nécessitent donc qu'un faible espace sur le disque,
  • Nativement client/serveur, architecture logicielle réfléchie: Subversion a été pensé dès le début en tant que client/serveur; évitant ainsi les problèmes de maintenance qu'a pu rencontrer CVS. Le code est structuré sous forme de modules donc les points d'entrée sont bien définis ce qui permettra de les utiliser depuis des applications tiers,
  • Le protocole envoie le différentiel dans les 2 directions: Le protocole réseau n'envoie que les parties différentes des ressources entre les versions du client et du serveur (CVS envoie les différences uniquement du serveur vers le client, mais pas du client vers le serveur),
  • Les coûts sont proportionnels à la taille des changements et non des données: En général, le temps nécessaire à une opération Subversion est proportionnel à la taille des changements qui résultent de l'opération et non de la taille du projet dans lequel les changements interviennent. C'est une des propriétés du modèle de référentiel de Subversion,
  • Manipulation efficace des fichiers binaires: Subversion est aussi efficace avec les fichiers binaires qu'avec les fichiers texte, car il utilise un algorithme différentiel pour transmettre et stocker les révisions successives,
  • Sorties interprétables: Toutes les sorties en ligne de commandes du client Subversion sont humainement compréhensibles et interprétables automatiquement par un programme; l'utilisation de Subversion avec des scripts est une priorité importante.

La liste des fonctionnalités ci dessus est appelée à évoluer en raison de celles déjà planifiées pour les prochaines versions.

[modifier] Téléchargement

Subversion peut être téléchargé sous forme binaire pour différentes plateformes (RedHat Linux, Debian GNU/Linux, SuSE Linux, *BSD, Mac OS X et Windows) mais également sous la forme d'un paquetage de sources.

Que ce soit pour les sources ou les binaires, vous trouverez tous les liens utiles à l'adresse: http://subversion.tigris.org/project_packages.html.

Nous allons télécharger les sources pour les compiler sur un plateforme Linux. Pour cela, rendez-vous à l'adresse http://subversion.tigris.org/servlets/ProjectDocumentList?folderID=260.

Téléchargez la version qui vous convient le mieux. De mon coté je télécharge la dernière version .tar.gz pour la décompresser dans un répertoire temporaire avec la commande suivante (en vous plaçant dans ce répertoire):

tar xvzf subversion-1.0.0.tar.gz

[modifier] Compilation et installation du client et du module serveur

Subversion dépend d'autres projets. Comme nous allons utiliser le serveur Subversion à travers WebDAV nous devons utiliser le serveur Web Apache 2.x. Le serveur Apache apportera un grand nombre de fonctionnalités supplémentaires (LDAP, authentification basique, proxies, ...)

Apache doit déjà avoir été installé et son utilitaire APXS doit être accessible au programme de configuration de la compilation de Subversion. Si ce n'est pas le cas, vous devrez en ajouter le chemin après l'option --with-apxs (exemple: --with-apxs=/opt/httpd/bin/apxs). Lors de la phase de configuration de la compilation, Subversion recherchera toutes ses dépendances dont cet utilitaire nécessaire à la création du module Subversion pour Apache.

Subversion a également besoin de la librairie neon pour pouvoir fonctionner en tant que client WebDAV. Celle-ci est intégrée aux sources de Subversion ce qui réduira la complexité de l'installation.

Subversion utilise pour stocker le référentiel une base de données Berkeley DB. Il faut donc également avoir celle-ci sur votre système.

Vous pouvez (devez ?) également activer le support SSL pour le cryptage des transferts entre le client et le serveur. Si vous voulez utiliser SSL, suivez les instructions d'installation d'OpenSSL. Pour éviter de l'alourdir, cet article ne décriera pas l'installation de ce programme tiers mais produira tout de même une version fonctionnant aussi bien avec http:// et https://.

Voici donc la ligne de configuration que nous obtenons:

./configure --prefix=/opt/subversion-1.0.0 --with-apxs --with-ssl

Pour compiler Subversion, vous avez juste à faire:

make

Pour installer le module Apache et les fichiers Subversions qui viennent d'êtres compilés (client, utilitaires d'administration, pages de man, librairies, ...), il vous suffit de faire:

make install

Si cette installation se déroule correctement, les 2 lignes suivantes devraient être ajoutées automatiquement au fichier de configuration Apache 2:

LoadModule dav_svn_module modules/mod_dav_svn.so
LoadModule authz_svn_module modules/mod_authz_svn.so

Si ce n'est pas le cas, ajoutez les vous même.

Le module mod_authz_svn sert à définir finement les permissions d'accès à certaines parties du référentiel Subversion.

Vous devez ensuite ajouter l'accès aux binaires de Subversion qui se trouvent dans /opt/subversion-1.0.0/bin au PATH. Vous devez pour cela impacter le fichier /etc/profile.

[modifier] Création et configuration d'un référentiel

Avant d'utiliser un référentiel, il est normal de commencer par le créer. Pour cela, nous allons utiliser la commande svnadmin. Si vous essayer d'utiliser cette commande avec help, vous devriez obtenir la liste des sous-commandes disponibles avec celle-ci:

$ svnadmin help
general usage: svnadmin SUBCOMMAND REPOS_PATH [ARGS & OPTIONS ...]
Type "svnadmin help <subcommand>" for help on a specific subcommand.

Available subcommands:
create
deltify
dump
help (?, h)
hotcopy
list-dblogs
list-unused-dblogs
load
lstxns
recover
rmtxns
setlog
verify

La sous-commande qui va nous servir dans l'immédiat est create. Si vous tapez la commande svnadmin create, vous obtiendrez:

svn: Repository argument required
create: usage: svnadmin create REPOS_PATH

Create a new, empty repository at REPOS_PATH.

Valid options:
--bdb-txn-nosync : disable fsync at transaction commit [Berkeley DB]
--bdb-log-keep : disable automatic log file removal [Berkeley DB]
--config-dir arg : read user configuration files from directory ARG

Comme nous le voyons, la sous-commande create attend le chemin du référentiel. La sous-commande create demande à ce que l'ensemble des répertoires nécessaires pour atteindre le référentiel lui-même existent:

mkdir /svn
svnadmin create /svn/test

Comme cela a déjà été indiqué, nous allons utiliser Apache comme serveur (avec le module Subversion). Dans le fichier de configuration d'Apache, 2 directives permettent de définir le nom d'utilisateur et le groupe avec lequel un processus enfant d'Apache sera créé. Dans mon cas, j'ai ceci:

User nobody
Group nogroup

Comme le module Subversion doit être en mesure d'effectuer des modifications dans le référentiel, il est normal de modifier les droits d'accès sur son arborescence:

chown -R nobody:nogroup /svn/test

L'étape suivante est la déclaration de ce référentiel au niveau Apache. Nous ajoutons donc les lignes suivantes:

<Location /test>
DAV svn
SVNPath /svn/test
</Location>

Si vous ne savez pas ou se trouve le fichier de configuration d'Apache, vous pouvez utiliser la commande "Apache -V" (dans le répertoire des binaires d'Apache) et vous devriez retrouver le fichier utilisé par Apache sur une ligne concernant la variable SERVER_CONFIG_FILE. Généralement, ce fichier se trouve dans le répertoire conf d'Apache et porte le nom httpd.conf.

La directive DAV svn permet d'activer WebDAV pour Subversion. La seconde ligne, SVNPath /svn/test, permet quant à elle de définir le chemin d'accès à notre référentiel.

Une fois ces modifications effectuées, il ne reste plus qu'à relancer Apache en faisant:

/etc/init.d/apache2 restart

Il est fort probable que vous deviez utiliser une commande légèrement différente chez vous car suivant les distributions Linux, les noms des répertoires/scripts peuvent être différents.

Pour tester que tout fonctionne bien, il ne vous reste plus qu'à lancer votre meilleur navigateur et de saisir l'URL: http://localhost/test.


Nous voyons donc qu'il est très simple de déclarer un serveur simple (sans authentification) avec Subversion.

[modifier] Conversion d'un référentiel CVS

Une fois que vous aurez goûté à Subversion, il y a de grandes chances pour que vous ne vouliez plus changer de système de contrôle des versions. Lorsque vous avez un ou des référentiels CVS, il est peut-être temps de les convertir pour Subversion.

Cette opération est facilitée grâce à un outil fournit avec Subversion. Il s'agit d'un script Python ce qui vous impose d'avoir Python installé et prêt à l'emploi sur votre machine.

Attention
L'opération de conversion d'un référentiel CVS à Subversion est une opération irréversible. Bien que non destructive envers le référentiel CVS original, il est évident que si vous effectuez cette opération, il sera difficile de réinjecter les modifications effectuées du référentiel Subversion vers le référentiel CVS original.

Cet utilitaire n'est pas installé lors de l'installation de Subversion (le make install). Vous le trouverez avec les sources de Subversion dans un répertoire tools/cvs2svn.

Si vous exécutez le script cvs2svn.py vous obtiendrez ceci:

USAGE: cvs2svn.py [-n] [-v] [-s svn-repos-path] [-p pass] cvs-repos-path
--help, -h print this usage message and exit with success
-n dry run; parse CVS repos, but do not construct SVN repos
-v verbose
-s PATH path for SVN repos
-p NUM start at pass NUM of 5
--create create a new SVN repository
--dumpfile=PATH name of intermediate svn dumpfile
--svnadmin=PATH path to the svnadmin program
--trunk-only convert only trunk commits, not tags nor branches
--trunk=PATH path for trunk (default: trunk)
--branches=PATH path for branches (default: branches)
--tags=PATH path for tags (default: tags)
--no-prune don't prune empty directories
--dump-only just produce a dumpfile, don't commit to a repos
--encoding=ENC encoding of log messages in CVS repos (default: ascii)
--username=NAME default name when CVS repos has no name (default: unknown)
--skip-cleanup prevent the deletion of intermediate files (default: 0)
--cvs-revnums record CVS revision numbers as file properties (default: 0)

La commande que nous allons utiliser pour notre traitement sera create. Nous allons partir du principe que nous avons un référentiel CVS à convertir dans /cvs/cvstest. Voici dans ce cas la commande à exécuter:

cvs2svn.py --create -s /svn/testcvs /cvs/testcvs

Suite à l'exécution de cette commande, nous obtenons un certain nombre de lignes indiquant que la conversion se déroule comme il le faut:

----- pass 1 -----
/cvs/testcvs/readme.txt,v
/cvs/testcvs/CVSROOT/loginfo,v
/cvs/testcvs/CVSROOT/rcsinfo,v
/cvs/testcvs/CVSROOT/verifymsg,v
/cvs/testcvs/CVSROOT/commitinfo,v
/cvs/testcvs/CVSROOT/taginfo,v
/cvs/testcvs/CVSROOT/checkoutlist,v
/cvs/testcvs/CVSROOT/cvswrappers,v
/cvs/testcvs/CVSROOT/notify,v
/cvs/testcvs/CVSROOT/modules,v
/cvs/testcvs/CVSROOT/config,v
----- pass 2 -----
----- pass 3 -----
----- pass 4 -----
creating repos '/svn/testcvs'
committing: Sat Nov 22 16:17:54 2003, over 0 seconds
adding or changing 1.1 : 'trunk/CVSROOT/checkoutlist'
adding or changing 1.1 : 'trunk/CVSROOT/commitinfo'
adding or changing 1.1 : 'trunk/CVSROOT/config'
adding or changing 1.1 : 'trunk/CVSROOT/cvswrappers'
adding or changing 1.1 : 'trunk/CVSROOT/loginfo'
adding or changing 1.1 : 'trunk/CVSROOT/modules'
adding or changing 1.1 : 'trunk/CVSROOT/notify'
adding or changing 1.1 : 'trunk/CVSROOT/rcsinfo'
adding or changing 1.1 : 'trunk/CVSROOT/taginfo'
adding or changing 1.1 : 'trunk/CVSROOT/verifymsg'
new revision: 1
committing: Sat Nov 22 16:21:21 2003, over 0 seconds
loading revision 1 into '/svn/testcvs'
adding or changing 1.1 : 'trunk/readme.txt'
new revision: 2
Finishing branches:
Finishing tags:
loading revision 2 into '/svn/testcvs'
----- pass 5 -----
pass 1: 0 seconds
pass 2: 0 seconds
pass 3: 0 seconds
pass 4: 1 seconds
pass 5: 0 seconds
total: 1 seconds

Cette opération de conversion peut-être excessivement longue en fonction de la taille de votre référentiel CVS et surtout du nombre de commits qui sont intervenus dessus. Le script Python va pour chaque commit CVS créer un révision Subversion.

Notre référentiel Subversion est pratiquement utilisable. Il reste à modifier les propriétaires de l'arborescence pour qu'ils correspondent à ceux du fichier de configuration d'Apache:

chown -R nobody:nogroup /svn/testcvs

Il manque la déclaration de ce référentiel dans Apache (fichier httpd.conf):

<Location /testcvs>
DAV svn
SVNPath /svn/testcvs
</Location>

Une fois le serveur Apache redémarré, vous pouvez utiliser ce référentiel comme un référentiel Subversion normal.

[modifier] Le client en ligne de commandes de Subversion

Tout comme CVS, Subversion fournit un client en ligne de commandes. Pour connaitre les sous-commandes de ce client, il suffit de faire:

svn help

pour voir s'afficher ceci:

usage: svn <subcommand> [options] [args]
Type "svn help <subcommand>" for help on a specific subcommand.

Most subcommands take file and/or directory arguments, recursing
on the directories. If no arguments are supplied to such a
command, it will recurse on the current directory (inclusive) by
default.

Available subcommands:
add
blame (praise, annotate, ann)
cat
checkout (co)
cleanup
commit (ci)
copy (cp)
delete (del, remove, rm)
diff (di)
export
help (?, h)
import
info
list (ls)
log
merge
mkdir
move (mv, rename, ren)
propdel (pdel, pd)
propedit (pedit, pe)
propget (pget, pg)
proplist (plist, pl)
propset (pset, ps)
resolved
revert
status (stat, st)
switch (sw)
update (up)

Subversion is a tool for version control.
For additional information, see http://subversion.tigris.org/

On voit qu'un certain nombre de sous-commandes et de raccourcis sont les mêmes que pour CVS. Comme indiqué dans le tableau des fonctionnalités, c'était une volonté des concepteurs de Subversion qui souhaitaient garder une compatibilité avec CVS quand c'était possible.

Avant de commencer le travail, nous devons définir une variable d'environnement permettant au client Subversion de savoir quel éditeur utiliser pour renseigner les descriptions lors des commits. La variable à renseigner est SVN_EDITOR. Il suffit de la définir dans le /etc/profile ou le .profile de l'utilisateur comme suit:

export SVN_EDITOR=/usr/bin/vi

Nous allons maintenant étudier les sous-commandes de base de Subversion. Nous vous recommandons de vous reporter à la documentation en ligne (en anglais) de Subversion pour un examen plus complet de l'ensemble de celles-ci: Version Control with Subversion.

Attention
Veillez à toujours utiliser une commande Subversion quand elle existe pour manipuler les fichiers. N'utilisez pas les fonctions de votre système (déplacement, renommage, copie, ...) car sinon, Subversion sera incapable de suivre l'évolution des ressources dans votre copie de travail.

[modifier] checkout (abrégé co)

La sous-commande checkout permet de télécharger en local un copie de travail d'un référentiel. C'est la première étape à accomplir lorsque l'on désire travailler sur un projet. Voici un exemple d'utilisation (en vous plaçant dans le répertoire local où vous stockerez vos différentes copies de travail):

svn co http://localhost/test

Le client de Subversion ouvre une communication WebDAV avec le serveur et télécharge en local les fichiers nécessaires au développement du projet test.

[modifier] update (abrégé up)

Avant de commencer toute modification, il est bon de récupérer la dernière version du projet. Cette sous-commande permet de récupérer les dernières modifications des autres membres d'un projet. Son utilisation est toute simple (dans le répertoire de votre copie de travail):

svn up

Le client récupère alors la dernière version du projet.

add

Cette sous-commande est très proche de celle déjà existante avec CVS. Elle permet d'ajouter une ressource dans la liste des ressources qui appartiendront au référentiel. L'utilisation du futur ici est justifiée car l'opération ne sera effective qu'au moment du commit. Voici comment utiliser add (toujours dans le répertoire de la copie de travail):

svn add fichier.txt

Bien entendu, il faut que le fichier existe avant de l'ajouter.

A noter qu'il n'est pas nécessaire (contrairement à CVS) d'indiquer si le fichier est de type texte ou binaire: le client Subversion se charge de le déterminer.

[modifier] delete (abrégé del, remove ou rm)

La sous-commande delete permet de supprimer une ressource de la copie de travail. Cette modification prend un effet immédiat sur la copie de travail. Par contre, il faudra confirmer par commit cette modification pour impacter le référentiel. Exemple:

svn delete fichier.txt

[modifier] copy (abrégé cp)

Comme l'indique son nom, cette sous-commande permet de recopier une ressource d'un endroit du référentiel vers un autre endroit. Elle a un effet immédiat sur les ressources locales (la copie de travail). Pour prendre effet sur le référentiel, une sous-commande commit devra être utilisée:

svn copy fichier.txt rep/

Dans cet exemple, nous copions le fichier fichier.txt dans le répertoire rep/.

La sous-commande copy permet également de créer des branches et des tags. Reportez-vous à la suite de ce document pour en apprendre plus sur ces 2 notions.

[modifier] move (abrégé mv, rename ou ren)

Cette sous-commande a un double usage puisqu'elle permet de déplacer des ressources dans la copie locale (avant commit pour impacter le référentiel) mais elle sert également à renommer une ressource. Exemple:

svn move fichier.txt fichier.old

renomme le fichier fichier.txt en fichier.old.

svn move fichier.old rep/

déplace fichier.old dans le répertoire rep/.

[modifier] status (abrégé stat ou st)

Cette sous-commande permet de savoir si vous avez des fichiers différents de ce qu'il y a dans le référentiel (par encore ajoutés, non commités, ...). Son usage est simple:

svn status

[modifier] revert

Cette sous-commande permet d'annuler des modifications locales non encore commitées. Son usage est simple puisqu'il suffit d'indiquer le nom de la ressource que l'on souhaite récupérer du référentiel. Exemple:

svn revert fichier.txt

reviendra sur la version du référentiel de fichier.txt.

[modifier] log

Cette sous-commande permet de suivre l'évolution dans le temps d'une ressource du référentiel ou de la copie locale. Voici un exemple d'utilisation:

svn log fichier.txt

------------------------------------------------------------------------
r12 | (no author) | 2004-02-29 08:16:34 +0100 (Sun, 29 Feb 2004) | 2 lines

Application des patchs de la branche 1.1.

------------------------------------------------------------------------
r7 | (no author) | 2004-02-28 17:41:44 +0100 (Sat, 28 Feb 2004) | 2 lines

Modification du fichier

------------------------------------------------------------------------
r2 | (no author) | 2004-02-27 08:25:57 +0100 (Fri, 27 Feb 2004) | 2 lines

Ajout du premier fichier.

------------------------------------------------------------------------

La sous-commande log est particulièrement utile pour connaître les révisions utilisées pour fusionner des branches.

[modifier] merge

Cette sous-commande permet de fusionner les ressources des 2 branches vers le répertoire de travail. Voici un exemple d'utilisation:

svn merge http://localhost/test/trunk@head http://localhost/test/branches/1.1@head .

[modifier] commit

Cette sous-commande est l'une des plus connues puisque c'est elle qui va confirmer les changements que vous avez effectué sur votre copie de travail. Exemple:

svn commit

si vous avez bien déclaré la variable d'environnement SVN_EDITOR (voir plus haut), vous devriez voir un éditeur s'ouvrir vous proposant de saisir un commentaire qui sera assigné à vos modifications dans le référentiel. Voici un exemple:

--This line, and those below, will be ignored--

A fichier.txt

Dans cet exemple, nous savons que l'ajout du fichier, indiqué par la lettre A, sera confirmé dans le référentiel. Il faut alors saisir un commentaire au dessus de la ligne avec les deux tirets. Exemple:

Ajout d'un fichier pour montrer l'utilisation de commit.
--This line, and those below, will be ignored--

A fichier.txt

Lorsque vous sauvegarderez ce texte et quitterez l'éditeur, le commit sera effectivement effectué sur le référentiel.

Si au moment où vous êtes dans l'éditeur, vous voyez qu'un fichier ne doit pas être commité, vous pouvez simplement quitter cet éditeur sans sauver. Subversion vous demandera alors s'il faut quitter sans sauver (et ne pas commiter) ou s'il faut revenir à l'éditeur.

[modifier] Utiliser les branches et les tags

Deux notions sont particulièrement importantes avec un gestionnaire de versions: les branches et les tags (étiquettes).

Pour être concret, nous allons prendre l'exemple d'un projet arrivant à la version 1.0. Comme rien n'est parfait, le principal mainteneur du projet va créer ce que l'on appelle une étiquette 1.0 sur le projet (dans le référentiel) pour permettre de revenir sur cette version en cas de bogue. Cela permettra également aux personnes de pouvoir récupérer cette version à partie du référentiel. Voici comment nous pourrions représenter se marquage dans l'arbre de développement:

Afin de ne pas laisser dormir le projet, les développeurs continuent le développement du projet pour préparer la future version majeure: la 2.0.

Le projet ayant beaucoup de succès, des bogues sont remontés dans le gestionnaire de bogues (bugtracker). Comme il n'est pas possible de sortir pour le moment la version 2.0, qui n'est encore qu'en phase de développement, les développeurs chargés de maintenir la version 1.0 vont récupérer celle-ci dans le référentiel de Subversion (grâce à l'étiquette 1.0) pour commencer le développement d'une version mineure 1.1. Pour cela, ils créent une branche comme indiqué ci-dessous:

Ils effectuent les modifications nécessaires et appliquent les patchs (correctifs) envoyés par les utilisateurs de la version 1.0. Lorsque tout semble bon, ils versionnent cette correction et l'étiquettent 1.1 afin que les utilisateurs puissent maintenant télécharger cette nouvelle version:

Dès que tout semble bon, les développeurs reprennent le développement de la version majeure 2.0. Lorsque tout semble bon, ils la versionnent et la publient en 2.0:

Pour les projets plus ou moins importants, il est possible que les mêmes développeurs soient à la fois chargés de maintenir le projet existant et les projets versionnés et publiés. Ceci ne pose aucun problème car il est possible d'avoir des versions différentes d'un même projet (version 1.x, 2.x, version de développement) dans des répertoires différents du poste de développement.

Avant de commencer tout développement, une petite préparation du référentiel est nécessaire. Afin de gérer la version de développement, les branches et les tags, quelques répertoires doivent être créés par le mainteneur principal du projet. Il va créer 3 répertoires comme ceci (sur la même ligne):

svn mkdir http://localhost/test/trunk http://localhost/test/branches http://localhost/test/tags -m "Création des répertoires d'archivage Subversion."

Le répertoire trunk sera le tronc de l'arbre de développement. C'est dans ce répertoire que vous développerez normalement votre projet.

Le répertoire branches servira à stocker les branches conséquences de la création d'un correctif sur les versions antérieures à celle en cours de développement.

Enfin, le répertoire tags permettra de stocker les différentes versions officielles de votre projet. Il ne doit jamais y avoir de développement ici car ce répertoire ne recevra que des copies de trunk ou des branches.

Il faut comprendre que cette organisation n'est qu'une convention de nommage proposée par les créateurs de Subversion. Vous pouvez modifier le mode de gestion de votre référentiel mais ce serait un mauvais choix en raison des différentes documentations de Subversion qui l'utiliseront: les nouveaux développeurs du projet devront s'habituer à votre mode de fonctionnement ce qui n'est pas forcément une bonne chose.

Nous allons maintenant reprendre la description du projet fictif vu ci-dessus et montrer comment utiliser les branches et les tags avec Subversion.

[modifier] Développement de la version 1.0

Un développeur du projet ajoute un fichier fichier.txt dans le répertoire trunk de sa copie de travail. Une fois le fichier considéré comme stable, il l'ajoute dans le référentiel:

svn add trunk/fichier.txt
svn commit

Comme le développement de la première version qui sera rendue publique semble terminé, le mainteneur du projet créé une étiquette pour indiquer que ce sera la version 1.0. Celle-ci servira également de base au développement de correctifs à cette version publiée.

Attention
Il faut impérativement que l'ensemble des ressources qui appartiendront à cette version aient été commitées dans le référentiel . Après, il sera trop tard.
svn copy http://localhost/test/trunk http://localhost/test/tags/1.0

En faisant cela, Subversion crée des copies internes au référentiel sur les ressources contenues dans le répertoire trunk de notre projet. Par la même occasion, il vous demande de saisir un commentaire lié à la création de cette branche.

Comme cette copie n'est intervenue que dans le référentiel et pas sur la copie locale, il faut mettre à jour cette copie locale:

svn update

Le répertoire tags de la copie de travail est alors mis à jour.

[modifier] Développement de la version 2.0

Le développeur est très actif. Il commence déjà le développement de la prochaine version majeure du projet: la 2.0. Il effectue normalement ces modifications sur les ressources de trunk de sa copie locale du référentiel. A chaque fois qu'il pense avoir fait des modifications significatives de cette future version, il les commite:

svn commit

Les révisions se succèdent...

Comme personne n'est parfait, les premiers bogues de la version 1.0 sont remontés par les utilisateurs.

[modifier] Création d'une branche 1.1

Afin d'appliquer les différents correctifs qui lui sont remontés, le développeur va d'abord créer une branche à la version étiquetée 1.0 et mettre à jour son répertoire de travail:

svn copy http://localhost/test/tags/1.0 http://localhost/test/branches/1.1
svn update

Une fois cela effectué, le développeur peut appliquer les correctifs sur la branche 1.1 de son répertoire de travail. Dès que cela lui semble bon, il n'oublie pas de commiter ces modifications dans le référentiel.

svn commit

[modifier] Publication de la version 1.1

Comme tous les correctifs ont été appliqués et que tout semble bien fonctionner, le développeur se décide à publier la version 1.1. Pour faire cela, il va créer une nouvelle étiquette 1.1 qui sera publique pour les utilisateurs du projet et met à jour son environnement:

svn copy http://localhost/test/branches/1.1 http://localhost/test/tags/1.1
svn update

Il est possible de renouveler ces différentes opérations en créant une branche 1.2 à partir du tag 1.1 et ainsi de suite.

[modifier] Fusion de branches

Comme c'était indiqué plus haut, les utilisateurs de votre projet vous remonteront probablement des correctifs. Mais lorsque vous appliquez ceux-ci à une branche, il peut être nécessaire d'impacter également la version de développement de votre projet. C'est à cela que sert la sous-commande merge.

A chaque commit, un numéro de révision différent est attribué à cette validation: ces numéros sont simplement incrémentés d'une révision à l'autre. Pour fusionner 2 branches (le tronc étant lui aussi une branche), il est nécessaire de connaitre leur numéro de révision. C'est à cela que sert la sous-commande log. Voici ce que nous pourrions avoir sur la branche 1.1 du projet vu un peu plus haut:

$ svn log http://localhost/test/branches/1.1

------------------------------------------------------------------------
r5 | (no author) | 2004-02-28 15:26:04 +0100 (Sat, 28 Feb 2004) | 1 line

Application des patchs.
------------------------------------------------------------------------
r4 | (no author) | 2004-02-28 15:16:02 +0100 (Sat, 28 Feb 2004) | 1 line

Création de la branche 1.1
------------------------------------------------------------------------
r3 | (no author) | 2004-02-28 14:59:21 +0100 (Sat, 28 Feb 2004) | 1 line

Version 1.0
------------------------------------------------------------------------

alors que dans le tronc, nous obtenons:

$ svn log http://localhost/test/trunk

------------------------------------------------------------------------
r7 | (no author) | 2004-02-28 17:41:44 +0100 (Sat, 28 Feb 2004) | 1 line

Modification du fichier
------------------------------------------------------------------------
r2 | (no author) | 2004-02-27 08:25:57 +0100 (Fri, 27 Feb 2004) | 1 line

Ajout du premier fichier.
------------------------------------------------------------------------
r1 | (no author) | 2004-02-27 08:25:04 +0100 (Fri, 27 Feb 2004) | 1 line

Ajout des répertoires d'archivage.
------------------------------------------------------------------------

Comme vous le voyez, les numéros de révision ne se suivent obligatoirement pour la même ressource. Ceci est simplement dû au fait que le développement du projet n'est pas linéaire: vous pouvez développer sur l'arbre principal, puis sur une branche, revenir sur l'arbre principal, ...

Dans notre cas, nous souhaitons fusionner les patchs appliqués sur la r5 (c'est-à-dire la dernière révision de la branche 1.1) avec la révision r7 correspondant à la dernière révision de trunk. Le résultat sera alors placé dans le répertoire trunk de la copie de travail:

svn merge http://localhost/test/trunk@7 http://localhost/test/branches/1.1@5 trunk/

La première URL correspond à la révision considérée comme la plus ancienne (la plus "obsolète" au niveau du code) alors que la seconde est la plus récente. Il ne faut pas regarder dans ce cas les numéros de révision car le développement a pu continuer sur la branche principal du développement alors que la branche était en cours de test. C'est le cas de ce projet, ce qui explique que le numéro de révision de trunk est supérieur à celui de la branche.

Sachant que nous avons utilisé les 2 dernières révisions des 2 branches, nous aurions également pu écrire:

svn merge http://localhost/test/trunk@head http://localhost/test/branches/1.1@head trunk/

Une fois cela fait, il ne reste qu'à vérifier que tout fonctionne bien, puis à commiter le travail:

svn commit

[modifier] Utiliser plusieurs référentiels Subversion

Avec CVS, il est possible d'utiliser plusieurs référentiels déclarés avec des CVSROOT différents. Subversion fournit deux mécanismes qui permettent d'avoir plusieurs référentiels indépendants hébergés par un même serveur.

La première méthode est toute simple puisqu'il suffit de déclarer un SVNPath différent entre des balises <Location>. Voici un exemple:

<Location /repos1>
   DAV svn
   SVNPath /svn/repos1
</Location>

<Location /repos2>
   DAV svn
   SVNPath /svn/repos2
</Location>

<Location /repos3>
   DAV svn
   SVNPath /svn/repos3
</Location>

Cette méthode impose malheureusement un inconvénient de taille: il est nécessaire de modifier un fichier de configuration du serveur Apache mais aussi de redémarrer ce serveur à chaque ajout d'un référentiel.

Pour remédier à ce problème, il suffit simplement d'indiquer quelle est la racine des référentiels. Jusqu'à maintenant, nous avons créé nos différents référentiels dans le répertoire /svn. Ce sera donc ce répertoire qui servira de base. Dans le fichier httpd.conf, vous n'avez qu'à simplement déclarer une section <Location> comme ceci:

<Location /svn>
   DAV svn
   SVNParentPath /svn
</Location>

Une fois le serveur Apache redémarré, l'accès aux différents référentiels est très simple puisqu'il suffit d'indiquer comme URL:

http://localhost/svn/test
http://localhost/svn/testcvs

[modifier] Authentification

Jusqu'à maintenant, nous n'avons pas encore abordé l'aspect sécurité de Subversion. En effet, à aucun moment nous n'avons indiqué à Subversion un identifiant et un mot de passe comme nous pouvions le faire avec CVS. Ceci est très dommageable car en effet, cela signifie que toute personne ayant un accès réseau au référentiel est en mesure d'y effectuer des modifications. Il est donc temps de remédier à cela.

[modifier] Authentification basique

Tout au long de ce document, nous avons utilisé comme serveur réseau le serveur Web Apache. En utilisant ce dernier (à la place du serveur standalone de Subversion) nous profitons de tous les avantages qu'il donne pour effectuer des authentifications: basique, ldap, base de données, ...

Afin de ne pas complexifier les choses, nous allons montrer comment mettre en place une authentification basique (AuthType basic).

Pour commencer, nous allons modifier notre <Location> pour utiliser cette authentification:

<Location /test>
DAV svn
SVNPath /svn/test

# Indique comment authentifier les utilisateurs
AuthType Basic
AuthName "Référentiel Subversion"
AuthUserFile /svn/utilisateurs.txt
Require valid-user
</Location>

Ceci n'est pas très différent de ce que vous feriez avec Apache pour obliger l'authentification des visiteurs sur certaines URL.

Avec la directive AuthUserFile nous indiquons un fichier contenant la liste des utilisateurs et leur mot de passe crypté. Pour créer ce fichier, Apache fournit une utilitaire htpasswd. Pour l'utiliser ce n'est pas compliqué puisqu'il suffit de faire:

$ htpasswd -cm /svn/utilisateurs.txt jean
New password:********
Re-type new password:********
Adding password for user jean

Pour ajouter un autre utilisateur:

$ htpasswd -m /svn/utilisateurs.txt paul
New password:********
Re-type new password:********
Adding password for user paul

Afin que ce fichier ne puisse être lu ou écrit par un autre utilisateur que l'utilisateur Apache:

# chown nobody:nogroup /svn/utilisateurs.txt && chmod 600 /svn/utilisateurs.txt

Une fois Apache relancé, vous verrez qu'il n'est pas possible de se connecter au référentiel sans fournir des informations d'authentification. Si vous le faites depuis un navigateur Internet, voici ce que vous obtiendrez:


Saisissez alors l'identifiant et le mot de passe pour jean pour accéder au référentiel.

[modifier] Contrôle d'accès par répertoire

Nous venons de voir qu'il est possible de mettre en place une authentification qui se fait sur l'ensemble du référentiel. Mais dans la plupart des cas, les utilisateurs du référentiel (développeurs ou non du projet) ne doivent pas avoir les mêmes droits: quelques-un ne pourront que lire certaines parties du référentiel, d'autres auront tous les droits... Il faut donc un autre mécanisme pour définir beaucoup plus finement les permissions d'accès aux différents répertoires d'un référentiel.

Attention
La technique de contrôle d'accès proposée pourrait ne pas fonctionner sur votre version de Subversion si celle-ci n'est pas assez récente. En effet, un bogue sur les révisions précédentes à la révision 8892 de Subversion ne permettent le contrôle d'accès qu'avec la directive Subversion SVNPath. Il n'est pas possible sur ces révisions de l'utiliser avec SVNParentPath: issue #1588. La version officielle tarball intégrant cette révision devrait être la 1.0.1 ou la 1.1.0.

Pour mettre en oeuvre cela, il va falloir utiliser le module Subversion pour Apache: mod_authz_svn.so. Pour que ce module soit disponible, vous devriez avoir la ligne suivante dans le fichier httpd.conf de votre serveur Apache:

LoadModule authz_svn_module modules/mod_authz_svn.so

Nous allons devoir également modifier la <Location> comme suit:

<Location /test>
DAV svn
SVNPath /svn/test

# Indique comment authentifier les utilisateurs
AuthType Basic
AuthName "Référentiel Subversion"
AuthUserFile /svn/utilisateurs.txt
Require valid-user

AuthzSVNAccessFile /svn/perm.txt
</Location>

Le fichier perm.txt est un fichier texte ayant une syntaxe vraiment très simple à utiliser et à comprendre. En voici un exemple:

[groups]
dev = paul,jean

[/]
* = r

[/branches]
@dev = rw
* =

[/trunk]
@dev = rw

[/tags]
paul = rw

La première ligne de ce fichier, [groups], permet de définir des groupes d'utilisateurs. Dans notre cas, nous avons un groupe appelé dev qui contient 2 membres: paul et jean. Si une ligne est trop longue (car trop d'utilisateurs), il est possible de continuer sur la ligne suivante en ajoutant un anti-slash (\) à la fin de chaque ligne.

Nous voyons ensuite différentes parties du référentiel pour lesquelles on définit des accès différents. Toute permission donnée ou enlevée dans un répertoire à un effet sur ses sous-répertoires sauf si une nouvelle règle vient contredire celle-ci. C'est le cas par exemple avec le répertoire de base / pour lequel on autorise tout utilisateur à en lire le contenu mais également ses sous-répertoires.

Nous avons décidé que les simples visiteurs du référentiel ne devaient pas pouvoir lire le contenu des branches (qui sont des versions non stables avant publication dans le répertoire des tags). C'est pour cette raison que l'on indique que tout membre du groupe dev (groupe indiqué par le signe @) a le droit de lire ou écrire dans le répertoire /branches. Mais avec le * =, nous interdisons aussi bien la lecture que l'écriture dans ce répertoire pour tout autre utilisateur.

Nous permettons à tout utilisateur la lecture de /trunk (puisque nous l'avions autorisé avec * = r sur /) mais nous donnons des droits supplémentaires aux membres de dev en autorisant à la fois la lecture et l'écriture dans ce répertoire.

Enfin, pour le répertoire /tags, seul le mainteneur principal du projet paul sera en mesure d'y effectuer des écritures (création de nouvelles étiquettes) alors que les autres ne pourront y faire que des lectures.

A noter qu'il est possible de donner des droits beaucoup plus poussés en indiquant des sous-répertoires de /branches, /trunk ou /tags.

[modifier] Accès anonyme au référentiel

L'accès anonyme au référentiel n'est pas compliqué à mettre en oeuvre. Si vous avez bien suivi la précédente partie, Contrôle d'accès par répertoire, vous aurez remarqué que l'on utilisait * pour signifier tous les autres utilisateurs. Donc, si des utilisateurs n'ayant pas de compte Subversion veulent lire notre référentiel, ils devront utiliser un compte générique. On utilise souvent un compte anonymous sans mot de passe. Nous allons donc créer celui-ci avec htpasswd:

$ htpasswd -m /svn/utilisateurs.txt anonymous
New password:
Re-type new password:
Adding password for user anonymous

Si vous devez mettre un mot de passe, utiliser le mot de passe anonymous. C'est une convention aussi acceptée qui évitera aux visiteurs de référentiel de chercher quoi mettre.

[modifier] Utiliser le contrôle d'accès avec le client Subversion

L'utilisation du contrôle d'accès avec le client Subversion svn est très simple. A votre première requête sur le référentiel (normalement le checkout), vous devrez indiquer l'identifiant et le mot de passe que vous êtes en droit d'utiliser.

Voici un exemple:

svn co http://localhost/test --username=paul --password=motdepassedepaul

[modifier] Ressources

[modifier] Bibliographie

  • Version Control with Subversion (en anglais) de Ben Collins-Sussman, Brian W. Fitzpatrick et C. Michael Pilato, consultable en ligne.

[modifier] Liens

[modifier] Conclusion

Comme nous l'avons vu, Subversion possède beaucoup d'intérêts. C'est grâce à ceux-ci qu'il a de fortes chances de remplacer finalement assez rapidement son aîné CVS.