TuXxX Blog
Just another WordPress weblog
Just another WordPress weblog
Article publié dans Linux Magazine 94, mai 2007.
Copyright © 2007 – Nicolas Chuche
Cet article est un tutoriel pour le logiciel de gestion de versions SVK, qui est parti du constat que, ayant besoin de SVK et ne le connaissant pas bien, le meilleur moyen de le maîtriser était d’approfondir mes connaissances et de les organiser dans un tutoriel à destination d’un public le plus large possible.
L’installation de SVK est d’une simplicité légendaire s’il est disponible sous forme de paquets :
% sudo aptitude install svk # Debian et dérivées % sudo urpmi svk # Mandriva
Sous Windows il existe un portage trouvable ici http://home.comcast.net/~klight/svk/
Si aucun paquet de SVK n’existe pour votre distribution, vous allez devoir passer par un shell d’installation Perl, CPAN ou CPANPLUS.
% sudo cpan SVK # avec CPAN.pm % cpanp i SVK # avec CPANPLUS
Comme me le souffle un camarade, une installation « à la main » n’est pas des plus simples car il vous faudra installer ou compiler un Subversion avec les bindings Perl. Vous pourrez trouver de l’aide sur le wiki de SVK : http://svk.bestpractical.com/view/InstallingSVK.
La première étape est de créer un dépôt sur votre machine :
% svk depotmap --init Repository /home/test/.svk/local does not exist, create? (y/n)y
% svk mkdir //local/ -m 'creation du repertoire local' Committed revision 1.
La syntaxe normale pour récupérer les fichiers d’un dépôt centralisé est :
% svk checkout protocole://le.serveur.net/le/chemin/mon/appli repertoire
Quand vous allez taper cette commande pour la première fois, svk va vous poser trois questions :
% svk mirror --list Path Source ============================================================ //mirror/mesprojets https://mon.serveur.com/svn //mirror/mongueurs svn+ssh://autre.serveur.com/home/nc/.svk/local/local/mongueurs/trunk
Voyons maintenant un exemple (pour redmine, voir dans les références à la fin de cet article) :
% svk checkout svn://rubyforge.org/var/svn/redmine/ New URI encountered: svn://rubyforge.org/var/svn/redmine/ Choose a base URI to mirror from (press enter to use the full URI): [...] Depot path: [//mirror/redmine] [...] a)ll, h)ead, -count, revision? [a] Syncing svn://rubyforge.org/var/svn/redmine Retrieving log information from 1 to 21 Committed revision 10297 from revision 1. [...] Syncing //mirror/redmine(/mirror/redmine) in /home/nc/tmp/redmine to 10317.
% svk checkout svn://rubyforge.org/var/svn/redmine/trunk redmine % svk checkout https://rubyforge.org/var/svn/redmine/trunk redmine
Ou encore si vous avez accès au dépôt par ssh :
% svk checkout svn+ssh://rubyforge.org/var/svn/redmine/trunk redmine
Vous avez déjà un répertoire que vous souhaitez gérer avec SVK. La commande à utiliser est import :
% svk import --message 'import initial' monprojet/ //local/monprojet
monprojet/branches/ tags/ trunk/<tous vos fichiers et répertoires>
% svk checkout //local/monprojet/trunk monprojet
% svk import --message 'import initial' -t monprojet/ //local/monprojet
Plusieurs commandes vous seront utiles :
Vous donne un diff entre la version d’origine du dépôt et votre copie de travail. Cette commande peut prendre en argument un ou plusieurs fichiers/répertoires, vous ne verrez alors que leurs différences.
Ajoute des fichiers ou des répertoires dans le dépôt
Les fichiers ne seront réellement ajoutés qu’au prochain commit (cf point suivant).
% svk add rep A rep A rep/a A rep/b
Cette commande est récursive, si vous ajoutez un répertoire, tous les fichiers contenus seront également ajoutés.
Vous pouvez ajouter tous les nouveaux répertoires et fichiers d’un seul coup en faisant :
% svk add .
Un point intéressant à savoir, svk est (plus ou moins) intelligent, il n’ajoutera pas les fichiers de finissant par un « ~ » ainsi qu’un certain nombre d’autres motifs. La liste complète par défaut est : *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store
Permet d’enregistrer vos modifications dans le dépôt. Cette commande prend en option un commentaire, ce commentaire sert à décrire la ou les modifications apportées.
% svk ci -m 'quelques modifications' Committed revision 3.
Je vous suggère (fortement) d’être le plus précis possible dans les messages que vous associez aux commits. Cela vous permettra d’avoir une trace fiable.
Définition : révision
Cela fait déjà quelques fois que nous rencontrons ce terme de « révision » dans les sorties écran de svk. À chaque fois que vous faites un commit (ou une opération faisant un commit sans vous le dire comme par exemple pull ou smerge que nous verrons plus tard), svk va créer dans le dépôt un nouvel état du système de fichier contenant toutes vos modifications, ces états sont appelés des révisions.
Permet de supprimer un fichier dans le dépôt. Supprimer un fichier sur votre système de fichier n’avertit pas svk, cette commande lui précise que ce fichier n’existe plus. Dans le dépôt, svk ne supprime pas réellement le fichier, il garde bien sûr une trace de toutes les modifications qui y ont été apportées. Vous pourrez donc retrouver toutes ses versions si besoin est.
Permet de renommer un fichier ou un répertoire. Si vous déplacez le fichier par les commandes liées à votre OS, svk ne pourra pas le savoir. Vous devez utiliser cette commande :
% svk rename config/ etc/
Comme add et delete, cette commande ne prend effet réellement qu’après le prochain commit.
Permet de « défaire » les éditions locales. Si vous avez modifié un fichier ou bien exécuté une commande add ou delete par exemple mais que vous n’avez pas encore commité, vous pouvez revenir à l’état d’avant ce add ou ce delete :
% svk status # on crée un nouveau fichier % touch yyyyy # ce fichier est marqué comme inconnu par svk % svk status ? yyyyy # on l'ajoute par svk, il le marque comme à ajouter % svk add yyyyy A yyyyy # on le 'revert' % svk revert yyyyy Reverted yyyyy # il est à nouveau marqué comme inconnu % svk status ? yyyyy
Vous permet de voir rapidement l’état de vos fichiers
% svk status M a.c ! a.h ? b.c ? b.h
Le M indique que le fichier a été modifié, le ! que le fichier n’existe plus dans les fichiers locaux et le ? que le fichier n’existe pas dans le dépôt. Pour une liste complète, référez vous au SVK Book.
% svk update
% svk update Syncing //local/monprojet/trunk(/local/monprojet/trunk) in /home/test/monprojet to 6. Conflict found in a.c: e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e]
svk s’est rendu compte du problème et vous propose plusieurs choix. Dans l’immédiat nous n’allons utiliser qu’une des options (je vous laisse découvrir les autres), à savoir l’option "s". Cette dernière intègre les modifications apportées par les co-éditeurs du fichiers. À vous de rêgler le conflit :
% cat a.c >>>> YOUR VERSION a.c 115722413378427 #include "d.h" ==== ORIGINAL VERSION a.c 115722413378427 #include "b.h" ==== THEIR VERSION a.c 115722413378427 #include "e.h" <<<< 115722413378427
Après avoir résolu le conflit, vous devrez prévenir svk avec :
% svk resolved a.c
Et ensuite vous pourrez commiter cette modification afin de ne pas laisser traîner le conflit :
% svk commit a.c
Pour voir toutes les actions réalisées, vous pouvez faire svk log.
svk cat permet de voir l’état d’un fichier dans le dépôt. Nous verrons un peu plus loin un argument idéal à utiliser avec cette commande.
Voici quelques autres commandes qui pourront vous être utiles au cours de votre utilisation de svk :
% svk checkout --export //local/redmine/trunk redmine
% svk list //mirror articles/ monprojet/ mongueurs/ redmine/ tracks/
% svk mkdir monrepertoire % svk mkdir //local/quelquechose
% svk info Checkout Path: /home/nc/travail/rails/redmine Depot Path: //local/redmine/trunk/redmine Revision: 10389 Last Changed Rev.: 10389 Copied From: /mirror/redmine/trunk/redmine, Rev. 10375 Merged From: /mirror/redmine/trunk/redmine, Rev. 10388 % svk info //mirror/redmine Depot Path: //mirror/redmine Revision: 10410 Last Changed Rev.: 10388 Mirrored From: svn://rubyforge.org/var/svn/redmine, Rev. 22
% svk diff -r {2006-07-09}:{2006-07-10} === redmine/app/helpers/search_filter_helper.rb ================================================================== --- redmine/app/helpers/search_filter_helper.rb (revision 10337) +++ redmine/app/helpers/search_filter_helper.rb (revision 10340) @@ -29,10 +29,12 @@ end
Pour préciser que vous voulez comparer par rapport à la dernière version utilisez HEAD :
% svk diff -r {2006-07-09}:HEAD
% svk cat -r {2006-07-09} redmine/app/helpers/search_filter_helper.rb
checkout et update acceptent également un argument -r qui permet de préciser à partir de quelle révision on veut se mettre à jour.
% svk checkout --list Depot Path Path ======================================================================== //local/mesprojets/bbrails/trunk /home/nc/travail/rails/bbrails //local/mesprojets/fpw2006 /home/nc/travail/rails/fpw2006 //local/mesprojets/gestapp/trunk /home/nc/travail/rails/gestapp //local/mongueurs/trunk /home/nc/travail/mongueurs //local/redmine/trunk/redmine /home/nc/travail/rails/redmine ? //local/mesprojets/test /home/nc/tmp/prosper
% svk checkout --purge Purge checkout of //local/mesprojets/test to non-existing directory /home/nc/tmp/prosper? (y/n) y Checkout path '/home/nc/tmp/prosper' detached.
branches/ - les différentes versions de développement tags/ - des images figées trunk/ - la dernière version en cours de développement
La commande utilisée pour créer des tags et des branches est la même, il s’agit de svk copy :
% svk copy //local/monprojet/trunk \ //local/monprojet/branches/monprojet-1.0 \ -m 'creation de la branches 1.0' Committed revision 5.
% svk list //local/monprojet/branches/ monprojet-1.0/
% svk copy //local/monprojet/branches/monprojet-1.0 \ //local/monprojet/tags/monprojet-1.0 -m 'version 1.0 diffusée' Committed revision 7.
% svk switch //local/monprojet/branches/monprojet-1.0/
Pour repasser dans trunk il suffit de faire :
% svk switch //local/monprojet/trunk/
% svk smerge -Il //local/monprojet/branches/monprojet-1.0 \ //local/monprojet/trunk Auto-merging (0,/local/monprojet/branches/monprojet-1.0 to /local/monprojet/trunk (base /local/monprojet/trunk:4). ===> Auto-merging (0, 5) /local/monprojet/branches/monprojet-1.0 to /local/monprojet/trunk (base /local/monprojet/trunk:4). Empty merge. ===> Auto-merging (5,
/local/monprojet/branches/monprojet-1.0 to /local/monprojet/trunk (base /local/monprojet/trunk:4). U db/migrate/001_setup.rb New merge ticket: 0aca4fd4-bb1c-0410-adf5-ecdeea5a58f8: /local/monprojet/branches/monprojet-1.0:8 Committed revision 9.
% svk smerge -Il //local/monprojet/branches/monprojet-1.0 \ //local/monprojet/trunk Auto-merging (8, 11) /local/monprojet/branches/monprojet-1.0 to /local/monprojet/trunk (base /local/monprojet/branches/monprojet-1.0:8). ===> Auto-merging (8, 11) /local/monprojet/branches/monprojet-1.0 to /local/monprojet/trunk (base /local/monprojet/branches/monprojet-1.0:8). Conflict found in config/config_custom.rb: e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [e] e Waiting for editor... Merged config/config_custom.rb: a)ccept, e)dit, d)iff, m)erge, s)kip, t)heirs, y)ours, h)elp? [a] a G config/config_custom.rb New merge ticket: 0aca4fd4-bb1c-0410-adf5-ecdeea5a58f8: /local/monprojet/branches/monprojet-1.0:11 Committed revision 12.
% svk smerge -Il //local/monprojet/branches/monprojet-1.0 \ /ma/copie/de/travail
Aussi parfois appelé « cherry picking » (cueillette de cerise).
smerge ne sait pas faire ça, il va falloir se rabattre sur la commande merge.
% svk log ---------------------------------------------------------------------- r16: test | 2006-09-06 15:23:04 +0200 ajout d'une fonctionnalite pour la v2.0 ---------------------------------------------------------------------- r15: test | 2006-09-06 15:22:32 +0200 correction bug bloquant ---------------------------------------------------------------------- r14: test | 2006-09-06 15:22:14 +0200 ajout d'une fonctionnalite pour la v2.0
% svk diff -r 14:15 //local/monlogiciel/trunk/ === generate ================================================================== --- generate (revision 14) +++ generate (revision 15) @@ -1,4 +1,4 @@ #!/usr/bin/env ruby # commentaire -requir File.dirname(__FILE__) + '/../config/boot' +require File.dirname(__FILE__) + '/../config/boot' require 'commands/generate'
% svk merge -r 14:15 //local/monlogiciel/trunk/ U generate
Il vous faudra alors commiter ces modifications.
Créez une arborescence standard branches/tags/trunk
mkdir -p monlogiciel/{branches,tags,trunk}
Récupérez une archive de votre logiciel et décompactez-la directement dans trunk.
faites un import de toute l’arborescence
% svk import -m "premier import de monlogiciel" monlogiciel \ //local/monlogiciel
faites une copie de trunk vers une branche sur laquelle vous ferez vos modifications :
% svk copy -m "creation de la copie locale" //local/monlogiciel/trunk \ //local/monlogiciel/branches/monlogiciel-local
Une nouvelle version de monlogiciel est sortie, récupérez-la à nouveau et décompactez-la.
% svk import -m "import de monlogiciel v1.2" monlogiciel \ //local/monlogiciel/trunk
Essayez de fusionner le nouveau trunk avec votre version locale :
% svk smerge -C //local/monlogiciel/trunk \ //local/monlogiciel/branches/monlogiciel-local Auto-merging (2, 5) /local/monlogiciel/trunk to /local/monlogiciel/branches/monlogiciel-local (base /local/monlogiciel/trunk:2). U console New merge ticket: 6d4c1533-f1fa-4670-b606-7b3ba989afbe: /local/monlogiciel/trunk:5
% svk smerge -Il //local/monlogiciel/trunk \ //local/monlogiciel/branches/monlogiciel-local Auto-merging (2, 5) /local/monlogiciel/trunk to /local/monlogiciel/branches/monlogiciel-local (base /local/monlogiciel/trunk:2). ===> Auto-merging (2, 5) /local/monlogiciel/trunk to /local/monlogiciel/branches/monlogiciel-local (base /local/monlogiciel/trunk:2). U console New merge ticket: 6d4c1533-f1fa-4670-b606-7b3ba989afbe: /local/monlogiciel/trunk:5 Committed revision 6.
Recommencez la procédure ci-dessus ad-nauseam à chaque nouvelle version de votre logiciel.
projet/a.c /a.c-version_de_debuggage /a.c-1 /a.c-2 /a.c-bug_machin /...
Cela devient vite horrible et inutilisable (bien que des gens utilisent encore cette méthode).
% svk mirror https://rubyforge.org/var/svn/redmine/ //mirror/redmine % svk sync //mirror/redmine
Une fois cette étape réalisée, vous allez faire une copie locale des données récupérées :
% svk copy //mirror/redmine //local/redmine
% svk pull
% svk push
% svk diff //mirror/monprojet/ //local/monprojet/
% svk push --patch svk_correction_bug Auto-merging (10574, 10606) /local/mongueurs/trunk to /mirror/mongueurs/trunk (base /mirror/mongueurs/trunk:10604). Patching locally against mirror source svn://svn.mongueurs.net/articles. U magazines/Applications/svk.pod Patch svk_correction_bug created.
Le patch est déposé dans ~/.svk/patch.
Vous pouvez lister vos patchs en faisant :
% svk patch --list svk.pod@1: svk_correction_bug@1:
% svk patch apply svk_correction_bug
% svk depotmap remote /tmp/remote New depot map saved. Repository /tmp/remote does not exist, create? (y/n)y
Le dépôt est créé. On peut voir la liste des dépôts gérés par SVK en faisant :
% svk depotmap --list Depot Path ============================================================ // /home/nc/.svk/local /remote/ /tmp/remote
% svk list file:///tmp/remote
svk va vous poser des questions pour créer un miroir local dans le dépôt par défaut //. Répondez par défaut, cela va créer un nouveau chemin de dépôt //mirror/remote.
Synchronisez vos deux dépôts :
% svk sync //mirror/remote
Créez le répertoire monprojet qui va accueillir votre projet sur le miroir :
% svk mkdir //mirror/remote/monprojet/ \ -m 'creation du repertoire de monprojet'
Faites un smerge de votre dépôt local vers votre dépôt :
% svk smerge --baseless --incremental //local/monprojet \ //mirror/remote/monprojet
% svk smerge --incremental -m "mise a jour" //local/monprojet/ \ //mirror/remote/monprojet/
soit vous faites le smerge vu ci-dessus à la main de temps en temps.
% svk copy -m "creation" //mirror/remote/monprojet/ \ //local/monprojet-nouveau
Voila, vous pouvez maintenant faire un checkout de //local/monprojet-nouveau et travailler dessus :
% svk checkout //local/monprojet-nouveau % cd monprojet-nouveau % svk push Auto-merging (0, 13238) /local/monprojet-nouveau to /mirror/remote/monprojet (base /mirror/remote/monprojet:13223). ===> Auto-merging (0, 13238) /local/monprojet-nouveau to /mirror/remote/monprojet (base /mirror/remote/monprojet:13223). Merging back to mirror source file:///tmp/remote. Empty merge.
% ls ~/.svk/local/hooks post-commit.tmpl post-revprop-change.tmpl pre-commit.tmpl pre-revprop-change.tmpl start-commit.tmpl
Voici le hook utilisé dans le cas présent :
% cat ~/.svk/local/hooks/post-commit #!/bin/sh svk smerge --incremental //local/monprojet //mirror/remote/monprojet
Pensez à le rendre exécutable :
% chmod +x ~/.svk/local/hooks/post-commit
% svk proplist README % svk propset copyright 'NBC 2007' script/server M script/server % svk propset copyright 'NBC 2007' README M README % svk proplist README Properties on README: copyright % svk propget copyright README NBC 2007 % svk propdel copyright README M README % svk proplist README
% svk diff README Property changes on: README ___________________________________________________________________ Name: copyright +NBC 2007
Voici un certain nombre de propriétés utiles :
permet de rendre un fichier exécutable
% svk propset svn:executable 1 script/*
rendra tous les fichiers du répertoire script exécutables suite à une commande checkout ou update.
permet de traiter le « problème » des fins de ligne qui sont différentes suivant les systèmes d’exploitation. En utilisant la valeur « native », SVK utilisera automatiquement la fin de ligne normale du système sur lequel vous travaillez au moment de créer un fichier et non celle utilisée par le créateur du fichier :
% svk propset svn:eol-style native **/*.rb
Vous pouvez aussi forcer un type de fin de ligne en utilisant les valeurs CRLF, CR ou LF.
permet d’ignorer certains répertoires et fichiers qui n’ont pas à être journalisés :
% svk propset svn:ignore "*" tmp/
ignorera tous les fichiers créés dans tmp/
Vous pourrez trouver une liste plus complète des propriétés dans la documentation de Subversion http://svnbook.red-bean.com/. Attention, toutes les propriétés existantes dans Subversion ne sont pas forcément implémentées dans SVK.
[miscellany] global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store
[miscellany] enable-auto-props = yes [auto-props] *.rb = svn:eol-style=native *.pl = svn:eol-style=native *.png = svn:mime-type=image/png ...
Voici un diagramme récapitulant les flux des commandes importantes de SVK :
Sans doute la plus intéressante à première vue, la commande (svk commit --interactive) vous montre les différentes modifications effectuées et vous permet de sélectionner celles que vous voulez effectivement commiter, les autres restant à l’état de modifications dans votre copie de travail ;
Vous pouvez maintenant y appliquer des filtres (recherche par exemple) et modifier la sortie (standard, XML, …) ;
Les vues peuvent être vues comme les vues des bases de données ou comme des liens symboliques unix. Elles permettent de référencer une arborescence sous un autre nom (plus parlant).
Une liste complète des modifications de la version 2 est disponible sur le CPAN : http://search.cpan.org/src/CLKAO/SVK-v2.0.0/CHANGES
Seul inconvénient, mais de taille à mon avis, cette version n’est, sauf erreur, pas encore disponible en paquetage (sauf peut-être pour Mac OS X), vous devrez donc l’installer à la main. À moins d’en avoir besoin et de savoir ce que vous faites, je vous conseille de rester à la version installée par votre système de gestion de paquetages et d’attendre qu’elle soit disponible dans votre système d’exploitation ou distribution préféré. Ceci étant dit, cette nouvelle version fonctionne très bien pour moi depuis quelque temps déjà.
svk ls svn+ssh://mon.serveur.principal/home/nc/.svk/local/
svk pull //mirror/serveurprincipal/
pour gérer plus facilement la traduction de documents comme expliqué par le développeur de SVK lui-même : http://www.onlamp.com/pub/a/onlamp/2004/09/09/svk_translation.html.
vous pouvez imaginer versionner tout ou partie de votre répertoire personnel sous SVK et faire un miroir de tout cela sur vos différents ordinateurs. Cela permet d’avoir un backup à peu de frais et/ou de synchroniser certains fichiers intéressants (.zshrc, …)
il peut servir à un administrateur système pour versionner les fichiers de configuration de ses serveurs avec le gros avantages sur certains autres outils du même type de ne pas avoir besoin d’un répertoire spécial comme CVS ou .svn et de pouvoir importer sur place un répertoire. Imaginez par exemple que sur tous vos serveurs vous fassiez :
% svk import --to-checkout /etc/ //local/etc-serveur1
et qu’ensuite pour poussiez tout cela sur un serveur SVK centralisé grâce à la recette vu plus haut pour répliquer un dépot local sur un dépot distant. Cerise sur le gateau, vous pouvez même le faire sans ouvrir de trou dans votre pare-feu en utilisant les redirections de SSH.
Depuis votre serveur central vous pouvez voir toutes les modifications apportées à vos fichiers de configuration (bonjour ITIL). Vous pouvez comparer la version locale avec la version distante pour vérifier que rien n’a changé (voire automatiser cela et envoyer un mail en cas de changement).
Comme vous le voyez, les possibilités sont larges.
http://svk.elixus.org/ — La page du projet
http://svkbook.elixus.org/ — Le manuel (en cours d’écriture)
http://svk.bestpractical.com/ — Le wiki de SVK
http://www.redmine.org — rien à voir avec SVK mais c’est un application web de gestion de projets GPL qui mérite vraiment le détour. Simple, de bon gout et pourtant vraiment puissant.