title:      ★ Installer un dépôt Subversion sous Ubuntu
slug:       installer-un-depot-subversion-sous-ubuntu
date:       2006-07-07 16:50:09
type:       post
vignette:   images/logos/livre_subversion.png
contextual_title1:  ★ iPheeds.org, une version iPhone pour votre blog
contextual_url1:    20080723-ipheedsorg-une-version-iphone-pour-votre-blog
contextual_title2:  ★ Astuces et bonnes pratiques Django
contextual_url2:    20080211-astuces-et-bonnes-pratiques-django
contextual_title3:  ★ Des CSS de qualité
contextual_url3:    20070522-des-css-de-qualite

<p>Ce billet était parti pour être une <a href="https://larlet.fr/david/biologeek/archives/20060219-critiques-de-livres-aux-editions-eyrolles/">critique du livre</a> <a href="http://www.editions-eyrolles.com/Livre/9782212119190/subversion">Subversion, Pratique du développement collaboratif avec SVN</a> mais je pense qu'il est finalement plus intéressant de prendre un exemple concrêt comme il est suggéré dans le titre du livre, l'apprentissage de Subversion passe surtout par la pratique. Ayant quelques <a href="https://larlet.fr/david/biologeek/archives/20051203-convertisseur-de-syntaxes-wiki-dotclear-a-dokuwiki/">petits</a> <a href="https://larlet.fr/david/biologeek/archives/20051017-parser-un-fichier-pdb-en-python-facilement-et-efficacement/">scripts</a> à mon actif, c'était le moment où jamais de m'y mettre&nbsp;!</p>

<h2>Introduction</h2>


<p>Si vous ne savez pas ce qu'est <a href="http://subversion.tigris.org/">Subversion</a>, ce billet présente peu d'intérêt pour vous mais c'est toujours intéressant de savoir que ça existe au cas où vous pourriez en avoir besoin. Subversion est un réécriture de <abbr title="Concurrent Versions System">CVS</abbr> dont le principe est la gestion des versions concurrentes (la réécriture a permis <a href="http://fr.wikipedia.org/wiki/Subversion_%28logiciel%29#Les_apports_de_Subversion">de nombreuses améliorations</a>). Cela permet l'édition d'un même fichier par plusieurs personnes en même temps et la gestion de la traçabilité des modifications (qui a fait quoi et quand en gros). Un serveur possède donc une version commune et chaque développeur travaille sur sa propre version locale qu'il syncronise avec le serveur le plus souvent possible pour éviter les conflits avec les autres développeurs en précisant à chaque fois la nature de la modification effectuée. C'est bien sûr beaucoup plus puissant mais l'idée de base est là.</p>


<h2>Critique du livre</h2>


<p>Rapidemment quand même, ce livre est tout ce qu'il y a de plus fonctionnel, il permet de se familiariser avec les commandes usuelles à travers de nombreux exemples. J'ai choisi ce livre car je voulais connaître les bonnes pratiques au niveau de l'organisation du code dans un dépôt. C'est toujours intéressant avant de se lancer dans de gros projets et on trouve difficilement de la documentation là-dessus (alors que toutes les commandes le sont, elles sont même <a href="http://www.editions-eyrolles.com/Chapitres/9782212119190/Annexe_A_Mason.pdf?xd=59fff71b12c33d94add2ae7e699d70e3">directement en téléchargement sur le site d'Eyrolles</a> ce qui est pratique si vous cherchez une commande sans avoir le livre sous les yeux).</p>


<p>L'ouvrage est court mais traite toutes les questions que je me posais, de la création/gestion d'un projet à l'administration du serveur, en passant par l'utilité des branches de livraison et l'intégration d'un code tiers. Le seul léger manque est l'interfaçage avec Trac dont l'auteur ne fait même pas mention, ce serait d'ailleurs un ajout intéressant pour une prochaine édition. Heureusement il existe un <a href="http://projects.edgewall.com/trac/wiki/TracOnUbuntu">tutoriel en anglais</a> très bien fait sur le <a href="http://www.edgewall.com/trac/">site officiel</a> si vous souhaitez aller plus loin (un tutoriel a même été rédigé en français <a href="http://www.destination-linux.org/article52.html">sur Destination Linux</a>).</p>


<h2>Qu'est ce qui est «&nbsp;subversionable »&nbsp;?</h2>


<p>A peu près tout, même les binaires, mais encore faut-il que ça présente un intérêt. On stocke en général tout ce qui ne peut être généré dans le cas d'un projet de développement (par exemple vos fichiers compilés si vous possédez les sources c'est clairement inutile... sauf si votre projet est énorme bien sûr), mais certains y placent leurs sauvegardes, leur documentation, voire la totalité de leur /home, tout est possible, à vous de voir si c'est intéressant pour vous&nbsp;!</p>


<p>Personnellement, et dans le cadre de cet exemple, je n'y intègrerais que mes scripts python et plus particulièrement mon <a href="https://larlet.fr/david/biologeek/archives/20051017-parser-un-fichier-pdb-en-python-facilement-et-efficacement/">parser de fichiers PDB</a>. Il peut être intéressant d'y placer vos fichiers de configuration système si vous avez passé du temps à les personnaliser (par exemple vos .* dans votre home :-)).</p>


<h2>Création du dépôt</h2>


<p>Mon script actuel se situe dans&nbsp;:</p>


<pre>$ ll projects/PDBParser/</pre>

<blockquote><p>total 628
-rw-r--r-- 1 david david 101008 2006-04-20 12:00 1CDLA.pdb<br />
-rw-r--r-- 1 david david 450198 2005-10-12 00:25 1SDK.pdb<br />
-rw-r--r-- 1 david david  17992 2004-12-31 01:25 COPYING<br />
-rw------- 1 david david   9168 2006-04-20 13:14 PDBParser.py<br />
-rw------- 1 david david   3056 2006-04-20 13:20 README<br />
-rw-r--r-- 1 david david  10253 2006-04-20 13:20 README.html</p></blockquote>


<p>On va donc considérer que c'est ma copie locale de travail. Les fichiers *.pdb sont des données, COPYING contient la licence et README.html est généré à partir de README avec rst2html.</p>


<p>Pour l'exemple, je vais placer mon dépôt ou repository Subversion en local aussi à l'adresse suivante (assurez vous que ce dossier existe et que vous ayez les droits pour le faire)&nbsp;:</p>


<pre>$ mkdir /home/david/work/svn/repository
$ svnadmin create /home/david/work/svn/repository/</pre>


<p>Et effectuer l'import initial de mon code&nbsp;:</p>


<pre>$ svn import -m "Import initial du script" projects/PDBParser/ file:///home/david/work/svn/repository/PDBParser/trunk</pre>

<blockquote><p>Ajout          projects/PDBParser/README.html<br />
Ajout          projects/PDBParser/1SDK.pdb<br />
Ajout          projects/PDBParser/1CDLA.pdb<br />
Ajout          projects/PDBParser/COPYING<br />
Ajout          projects/PDBParser/PDBParser.py<br />
Ajout          projects/PDBParser/README <br /></p>
<p>
Révision 1 propagée.</p></blockquote>


<p>Petite vérification du statut de ma copie locale&nbsp;:</p>


<pre>$ svn status projects/PDBParser</pre>

<blockquote><p>?      projects/PDBParser/README.html<br />
?      projects/PDBParser/1SDK.pdb<br />
?      projects/PDBParser/1CDLA.pdb<br />
?      projects/PDBParser/COPYING<br />
?      projects/PDBParser/PDBParser.py<br />
?      projects/PDBParser/README<br />
!      projects/PDBParser</p></blockquote>


<p>Aïe, en fait il faut d'abord que ce dossier soit considéré comme une copie locale donc supprimons son contenu et récupérons ce que nous venons de placer sur le dépôt&nbsp;:</p>


<pre>$ rm projects/PDBParser/*
$ svn checkout file:///home/david/work/svn/repository/PDBParser/trunk projects/PDBParser</pre>

<blockquote><p>A    projects/PDBParser/README.html<br />
A    projects/PDBParser/1SDK.pdb<br />
A    projects/PDBParser/1CDLA.pdb<br />
A    projects/PDBParser/COPYING<br />
A    projects/PDBParser/PDBParser.py<br />
A    projects/PDBParser/README<br />
Révision 1 extraite.</p></blockquote>


<p>Ok, ça a marché, j'ai maintenant bien une copie locale de ce qui se trouve dans mon dépôt. Je peux commencer à travailler.</p>


<p>Ah non, j'ai dit que le README.html était généré via README donc inutile de le stocker dans le dépôt&nbsp;:</p>


<pre>$ svn propedit svn:ignore projects/PDBParser/</pre>


<p>Préciser <strong>*.html</strong> dans le fichier qui s'ouvre et le message suivant confirme sa prise en compte&nbsp;:</p>


<blockquote><p>Nouvelle valeur définie pour la propriété 'svn:ignore' sur 'projects/PDBParser'</p></blockquote>


<p>On enchaîne avec sa suppression&nbsp;:</p>


<pre>$ svn remove -m "Suppression de README.html car il est généré automatiquement" projects/PDBParser/README.html</pre>


<blockquote><p>svn: Opération locale sans propagation (commit), pas de message</p></blockquote>



<pre>$ svn commit -m "Mise à jour de la suppression de README.html" projects/PDBParser/</pre>


<blockquote><p>Envoi          projects/PDBParser<br />
<br />
Révision 2 propagée.</p></blockquote>



<h2>Mise à jour et release</h2>


<p>Maintenant que l'on a une copie locale fonctionnelle, passons à la modification du code. Prennez de bonnes habitudes en commençant par&nbsp;:</p>


<pre>$ svn update projects/PDBParser</pre>


<p>histoire d'être sûr d'avoir la dernière version du dépôt (dans notre cas c'est inutile mais si vous travaillez à plusieurs c'est primordial !).</p>


<p>Ok, je vais maintenant ajouter à la documentation une ligne indiquant la façon dont celle-ci est générée. Vous pouvez vérifier ce qui a été modifié via&nbsp;:</p>


<pre>$ svn diff projects/PDBParser</pre>


<p>Le retour dépend de vos modifications, c'est en général assez verbeux, si vous souhaitez juste connaître les fichiers ayant été modifiés&nbsp;:</p>


<pre>$ svn status projects/PDBParser</pre>

<blockquote><p>M      projects/PDBParser/README.html<br />
M      projects/PDBParser/README</p></blockquote>


<p>Le fichier README.html a aussi été modifié mais il ne devrait pas être mis à jour dans le dépôt puisqu'il est normalement ignoré. Allons-y pour le <strong>commit</strong> du code ajouté&nbsp;:</p>


<pre>$ svn commit -m "Ajout de la méthode de génération de la doc" projects/PDBParser/</pre>

<blockquote><p>Envoi          projects/PDBParser/README<br />
Envoi          projects/PDBParser/README.html<br />
Transmission des données ..<br />
Révision 3 propagée.</p></blockquote>


<p>Manifestement la propriété ignore a été ignorée... étrange, bon soit passons à la suite, je suis sûr qu'un gentil gourou se manifestera en commentaires ;-).</p>


<p>Vous pouvez à tout moment vérifier ce qu'il s'est passé sur votre projet grâce à&nbsp;:</p>


<pre>$ svn log projects/PDBParser</pre>


<p>Ok, j'ai une nouvelle version et j'ai décidé de faire une release de mon script. Il va pour cela falloir créer une branche de livraison et comme j'en suis à la version 3 on va l'appeler <strong>branche-livraison-3.1</strong> et la placer dans <strong>repository/branches</strong> (on commence par créer les répertoires en question)&nbsp;:</p>


<pre>$ svn mkdir -m "Création des branches" file:///home/david/work/svn/repository/PDBParser/branches
$ svn mkdir -m "Création de la branche de livraison 3.1" file:///home/david/work/svn/repository/PDBParser/branches/branche-livraison-3.1
$ svn copy -m "Branche de livraison 3.1 créée après correction du README" file:///home/david/work/svn/repository/PDBParser/trunk file:///home/david/work/svn/repository/PDBParser/branches/branche-livraison-3.1</pre>


<blockquote><p>Différence entre les branches et les livraisons&nbsp;?</p>
<p>
C'est assez simple, une branche est créée pour pouvoir être modifiée en cas de bug dans la version de la branche. En revanche, un tag de livraison est placé lorsque l'on veut connaître l'état du code à un instant t donné. Ainsi la branche 3.1 va être dans un premier temps taguée 3.1 puis s'il y a correction d'un bug mineur, pouvoir ensuite être taguée par exemple 3.1.1 et ainsi de suite.</p></blockquote>


<p>Une fois la branche crée, il suffit de la taguer pour obtenir une livraison. On crée pour cela le répertoire de <strong>repository/tags</strong>, puis la marque de livraison que l'on appelera <strong>livraison-3.1</strong>&nbsp;:</p>


<pre>$ svn mkdir -m "Création des tags" file:///home/david/work/svn/repository/PDBParser/tags
$ svn copy -m "Livraison 3.1 créée après correction du README" file:///home/david/work/svn/repository/PDBParser/branches/branche-livraison-3.1 file:///home/david/work/svn/repository/PDBParser/tags/livraison-3.1</pre>


<p>Il suffit ensuite de récupérer cette copie où l'on veut (créer le dossier avant) pour créer l'archive&nbsp;:</p>


<pre>$ svn checkout file:///home/david/work/svn/repository/PDBParser/tags/livraison-3.1/trunk current/PDBParser-3.1</pre>


<p>Et voila, plus qu'à compresser tout ça (sans les répertoires cachés ça fait plus pro).</p>


<p>Bon après je pourrais écrire des pages et des pages sur comment corriger un bug dans une branche particulière, switcher entre vos différentes versions, etc... mais tout a déjà été résumé dans un excellent bouquin :-). Le prochain <a href="https://larlet.fr/david/biologeek/archives/20060219-critiques-de-livres-aux-editions-eyrolles/">livre commenté</a> sera très certainement Zope, troisième édition mais c'est un pavé de 800 pages donc ça prend du temps (surtout qu'il est plutôt dense !). D'ici là de nouveaux <a href="https://larlet.fr/david/biologeek/archives/20060617-traduction-francaise-de-la-documentation-de-django-le-framework-web-python/">tutoriaux pour le framework web Django</a> devraient arriver.</p>


<h2>Export et sauvegardes</h2>


<p>Je viens de me rendre compte qu'il manquait une chose essentielle&nbsp;: l'export du dépôt pour effectuer une sauvegarde&nbsp;! Avec Subversion, les propagations sont atomiques, les modifications sont soit complètement propagées, soit complètement annulées pour assurer la cohérence du système au même titre qu'une base de données. Mais attention justement, il ne faut pas faire une simple sauvegarde du dossier contenant le dépôt mais un <strong>dump</strong> du dépôt pour sauvegarder des données cohérentes même en cas de mise à jour par un autre utilisateur au même instant.</p>


<p>Une sauvegarde complète s'effectue donc simplement&nbsp;:</p>


<pre>$ svnadmin dump work/svn/repository/ &gt; svn_repos.20060707</pre>

<blockquote><p>* Révision 0 déchargée.<br />
* Révision 1 déchargée.<br />
* Révision 2 déchargée.<br />
* Révision 3 déchargée.<br />
* Révision 4 déchargée.<br />
* Révision 5 déchargée.<br />
* Révision 6 déchargée.<br />
* Révision 7 déchargée.<br />
* Révision 8 déchargée.</p></blockquote>


<p>Il est préférable pour des sauvegardes quotidiennes si vous avez un dépôt conséquent de faire des sauvegardes incrémentales (option <strong>--incremental</strong> de <strong>svnadmin dump</strong>) pour ne pas tout sauver à chaque fois.</p>


<p>En cas de problème, il suffit de créer un nouveau dépôt et de recharger vos données&nbsp;:</p>


<pre>$ svnadmin create /home/david/work/svn/repository2/
$ svnadmin load /home/david/work/svn/repository2/repository2 &lt; svn_repos.20060707</pre>


<p>Et toutes les transactions sont effectuées dans votre nouveau dépôt. N'oubliez jamais qu'on regrette de ne pas faire de sauvegarde que lorsqu'on perd ses données... un petit script automatique prend une heure à trouver/adapter/mettre en place mais peut sauver des heures et des heures de développement, et ça n'arrive malheureusement pas qu'aux autres&nbsp;! Au même titre que le célèbre "No test, no commit", je serais tenté d'écrire "No backup, no admin".</p>
