SVK

Article publié dans Linux Magazine 94, mai 2007.

Copyright © 2007 – Nicolas Chuche

Chapeau de l’article

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.

Introduction

Pour Wikipédia, la gestion de versions est « une activité qui consiste à maintenir l’ensemble des versions d’un logiciel ». Si vous êtes développeur, il y a de bonnes chances que vous ayez à gérer cette activité et que vous connaissiez déjà un outil de gestion de versions comme CVS, Subversion ou équivalent.

Écrit il y a plus de 20 ans, CVS est sans doute le grand-père le plus connu des outils de gestion de versions libre. Bien qu’encore très utilisé de par le monde, il a un certain nombre de faiblesses gênantes (impossible de déplacer des fichiers en conservant l’historique, pas d’atomicité des transactions, pas de dépôts décentralisés, etc.) que les nouveaux outils n’ont plus.

De nombreux remplaçants ont vu le jour. Certains sont généralistes (Bazaar, Subversion, SVK, Mercurial, etc.) tandis que d’autres sont développés spécifiquement pour un projet (Git pour le noyau linux).

Dans cet article, je parlerai de SVK qui est un client. Pourquoi celui-ci et pas un autre ? Plusieurs raisons à cela :

SVK a été développé en 2003 par Chia-liang Kao pour ses besoins. Il s’est appuyé sur le système de fichiers de Subversion (svn) et a redéveloppé toute la couche haute. Les commandes utilisées sont néanmoins très proches de celle de Subversion et de CVS, les utilisateurs de ces produits ne seront donc pas totalement dépaysés. SVK a été acquis par Best Practical (le fameux éditeur de Request Tracker) en 2006 et Chia-liang Kao est devenu partenaire de Jesse Vincent chez Best Practical.

Installation

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.

Utilisation simple

Avant d’entrer dans le vif du sujet, nous allons aborder quelques notions utilisées par les logiciels de gestion de versions, et par SVK en particulier.

Pour ne pas vous surcharger dès l’introduction de notions plus ou moins complexes sans avoir pratiqué, je reviendrai au fur et à mesure de cet article sur quelques autres notions importantes.

Création d’un dépôt local

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

Comme indiqué dans le retour de la commande, elle crée votre dépôt dans votre répertoire personnel dans le répertoire .svk/local.

Afin de promouvoir le plus tôt possible les bonnes pratiques, nous allons dès maintenant structurer le contenu de ce dépôt de façon à organiser judicieusement les travaux à venir. Nous verrons plus tard l’intérêt direct de l’organisation proposée.

  % svk mkdir //local/ -m 'creation du repertoire local'
  Committed revision 1.

Quand je parle de répertoire, il s’agit bel et bien de cela. Mais celui-ci n’est pas sur votre système de fichier, il se trouve dans le dépôt SVK, c’est pour cela qu’on les appelle « depot path » ou « chemin de dépôt ». Pour ne pas confondre les chemins du système de fichier avec ceux du dépôt SVK, le chemin de dépôt par défaut est préfixé de deux slashes (/). //local est donc votre premier chemin de dépôt.

Travailler sur un projet déjà dans un dépôt

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 :

Juste pour information, nous venons de voir notre second chemin de dépot à savoir //mirror/. Celui-ci est en fait un chemin spécial qui, par convention, sert à stocker tous les miroirs que l’on va faire avec SVK. Vous pourrez voir la liste de tous les miroirs que vous avez créés en faisant :

  % 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.

Toutes les commandes de svk peuvent être raccourcies. En l’occurrence, le raccourci de checkout est co.

Si le dépôt utilise un serveur SVN, le protocole sera svn, si le serveur utilise WebDAV, le protocole sera http ou https :

  % 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û remarquer que j’ai utilisé le chemin /var/svn/redmine/trunk. Pourquoi trunk (tronc en français), pourquoi pas directement redmine ? Parce que trunk représente le développement principal et qu’il y a également des répertoires tags et branches permettant des « branches » de développements parallèles ainsi que la conservation de versions particulièrement intéressantes, mais n’avançons pas trop vite, nous verrons un peu plus loin pourquoi et comment nous en servir.

Créer un nouveau projet à partir de fichiers existants

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

Avant de passer cette commande, je vous suggère fortement à la lumière de notre (très) rapide aperçu des branches, tags et trunk d’organiser un peu vos répertoires. Déplacez vos fichiers de travail dans trunk et créez les répertoires branches et tags afin d’obtenir dès maintenant une organisation comme celle-ci :

  monprojet/branches/
            tags/
            trunk/<tous vos fichiers et répertoires>

Nous voyons maintenant à quoi nous sert d’avoir créé le répertoire //local. Cela permet de placer vos projets dans une arborescence dédiée et de ne pas tout avoir à la racine de votre dépôt.

Une fois l’import réalisé, vous allez pouvoir faire un checkout comme vu dans la partie précédente et commencer à travailler réellement. Pour ne récupérer que la version en cours de développement (soit trunk) et non toute l’arborescence, la commande à passer est :

  % svk checkout //local/monprojet/trunk monprojet

Vous auriez pu transformer directement le répertoire utilisé en version de travail en ajoutant l’option --to-checkout (ou -t) :

  % svk import --message 'import initial' -t monprojet/ //local/monprojet

Travailler sur votre projet

Ça y est, vous avez bien avancé sur votre nouvelle implémentation de logiciel de blog et vous voulez passer en revue vos modifications.

Plusieurs commandes vous seront utiles :

  • svk diff

    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.

  • svk add

    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

  • svk commit

    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.

  • svk delete

    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.

  • svk rename

    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.

  • svk revert

    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
  • svk status

    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.

Mettre à jour les fichiers locaux à partir du dépôt

Si vous êtes plusieurs à travailler sur votre projet, vous allez vouloir à un moment ou à un autre mettre à jour vos fichiers. Pour cela, utilisez la commande suivante depuis le répertoire de travail :

  % svk update

Le problème que vous voyez peut-être déjà c’est comment ça se passe si votre collègue/copain a modifié un fichier que vous avez modifié localement vous aussi. Voyons ça :

  % 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

Comme indiqué dans le texte, svk indique les différentes versions à l’origine du conflit à savoir, votre version actuelle, la dernière version commitée ainsi que la version du co-éditeur.

La résolution d’un conflit de ce type n’est pas tant un problème informatique que humain. Pour le résoudre vous aurez sans doute besoin de contacter la personne ayant fait la modification pour en parler avec elle avant de garder ou de modifier la version adéquate.

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

Une chose à savoir, les commandes commit et update ne sont pas liées. Vous pouvez faire (et ferez souvent) l’une sans l’autre.

Regarder l’historique des modifications

Pour voir toutes les actions réalisées, vous pouvez faire svk log.

Cette commande ne fait que vous afficher les commentaires que vous mettez quand vous commitez, c’est donc dans votre intérêt d’être le plus précis possible.

Par défaut svk log ne vous montre que l’historique que depuis la dernière copie effectuée. Si vous travaillez sur un miroir, vous devrez utiliser l’option --cross qui permet de voir également les modifications recopiées depuis un autre dépôt. L’option --verbose permet d’avoir une sortie un peu plus complète (fichiers concernés entre autre).

Pour regarder plus précisément un fichier, la commande svk annotate peut vous aider, elle permet de voir quelles lignes viennent de quelle version.

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.

Quelques autres commandes

Voici quelques autres commandes qui pourront vous être utiles au cours de votre utilisation de svk :

Quelques options bien utiles

Un certain nombre de commandes acceptent des arguments. Vous trouverez la liste complète dans le SVK Book mais je vais rapidement donner ici celles qui peuvent vous être utile tout de suite :

Les commandes diff, log, update et cat acceptent un argument -r pour indiquer une révision. Cet argument est soit le numéro de révision, soit une date. Par exemple, pour avoir les modifications faites entre le 9 juillet et le 10 juillet il suffit de faire :

  % 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

Et comme promis antérieurement, cette option est très pratique avec svk cat pour voir l’état d’un fichier dans telle révision ou à telle date :

  % 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.

Nous avons déjà vu la commande checkout. Elle dispose d’une option bien pratique au bout de quelque temps pour retrouver ses petits, il s’agit de --list qui affiche la liste des répertoires de travail :

  % 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

Le ? indique que le répertoire de travail n’existe plus. Vous pouvez alors supprimer cette référence en faisant :

  % 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.

Ça y est vous maîtrisez les commandes de base et vous pouvez utiliser SVK au quotidien mais il serait dommage de s’arrêter là alors qu’il y a tant à faire. Ceci nous amène naturellement sur le chapitre suivant ‘utilisation avancée

Utilisation avancée

Les branches et les tags

Cette partie demande quelques explications. Imaginons que vous écriviez un nouveau logiciel allant révolutionner le monde (un logiciel de blog par exemple). Vous venez de sortir la version 1.0 et vous voudriez bien pouvoir développer la future version 2.0, tout en continuant à corriger les bugs de la version 1.0. Pour utiliser le jargon, vous aimeriez bien avoir plusieurs branches de développement, une branche stable et une branche instable. Une solution simple existe dans la plupart des logiciels de gestion de versions, la notion de tag et de branches.

Les mises en œuvre de ces mécanismes différent d’un logiciel à l’autre mais pour SVK, cela se traduit tout simplement par trois répertoires créés dans le dépôt (et non au niveau du système de fichier) :

  branches/ - les différentes versions de développement
  tags/     - des images figées
  trunk/    - la dernière version en cours de développement

Dans SVK nous verrons que branches et tags sont gérés de la même façon, ils ne différent que par l’utilisation que l’on en fait : les branches sont utilisées pour développer les différentes versions en parallèle, tandis que les tags servent à conserver des versions spécifiques sur lesquelles vous ne travaillez pas. On ne commite pas dans les tags.

Création de branches et de tags

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.

Comme tout le monde s’en doutait, cela va créer un nouveau répertoire de dépôt dans branches contenant tous les fichiers dans l’état actuel de trunk :

  % svk list //local/monprojet/branches/
  monprojet-1.0/

Vous allez pouvoir faire un checkout de cette version 1.0 et travailler dessus tout en continuant à développer la version future dans trunk.

Une fois votre version 1.0 prête à être diffusée, vous voudriez bien garder une trace exacte de cette version. Bien sûr, vous pourriez utiliser l’option -r, que nous avons vue à la fin du chapitre précédent, avec le numéro de révision ou bien la date mais ça n’est pas très intuitif. Une meilleure façon est de tagger cette version :

  % svk copy //local/monprojet/branches/monprojet-1.0 \
     //local/monprojet/tags/monprojet-1.0 -m 'version 1.0 diffusée'
  Committed revision 7.

Un utilisateur vous soumet un bug ? Vous corrigez le bug dans la branche version-1.0 et quand vous diffusez une version 1.0.1 vous n’avez qu’à la copier dans tags sous le nom monprojet-1.0.1 pour en garder une trace.

Même si SVK s’arrêtait là la notion de tags et de branches serait un outil fantastique mais heureusement, SVK va beaucoup plus loin…

Passer votre copie de travail d’une branche à une autre

Si votre copie de travail est un checkout d’une branche et que vous voulez passer dans une autre, placez-vous dans le répertoire de la copie de travail et utilisez la commande svk switch :

  % svk switch //local/monprojet/branches/monprojet-1.0/

Pour repasser dans trunk il suffit de faire :

  % svk switch //local/monprojet/trunk/

La fusion

Vous avez vos deux versions, celle de trunk et celle de version-1.0. Vous corrigez plusieurs bugs dans version-1.0 et vous aimeriez bien les corriger aussi dans trunk. Plutôt que de reporter vos corrections à la main dans trunk, vous pouvez utilisez la fonction smerge :

  % svk smerge -Il //local/monprojet/branches/monprojet-1.0 \
    //local/monprojet/trunk
  Auto-merging (0, 8) /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, 8) /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.

Cette commande va reporter toutes les modifications que vous avez faites dans version-1.0 dans le trunk. Évidemment, si vous avez déjà modifié le trunk dans un endroit où vous avez également corrigé un bug vous risquez d’avoir un conflit, charge à vous de le résoudre.

Attention, contrairement à la résolution de conflit que nous avons vue précédemment, vous ne pourrez pas faire skip pour résoudre votre problème plus tard. Vous devrez le résoudre tout de suite grâce aux options diff (pour voir le conflit) et edit (pour le modifier). Si vous faites skip, cette partie ne sera pas fusionnée, néanmoins vous pourrez la refusionner plus tard. Suite à votre édition, svk vous demandera si vous voulez accepter la modification :

  % 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.

Une bonne méthode de travail consiste à regarder avant de faire le svk smerge si vous allez avoir des conflits en faisant utilisant l’option -C : svk smerge -C.

Quelques jours après cette fusion corrigeant des bugs, vos utilisateurs vous soumettent à nouveau plusieurs bugs bloquants. Vous les corrigez et vous aimeriez bien pouvoir faire la même manipulation pour les corriger dans trunk. Et bien j’ai une bonne nouvelle, vous pouvez la recommencer autant de fois que vous le voulez. Contrairement à certains autres logiciels (dont SVN et CVS entre autres) pour lesquels les fusions à répétitions entre branches sont non triviales (il faut préciser à la fonction merge la dernière révision pour laquelle on a déjà fait une fusion), SVK implémente dans smerge une fonction de fusion sophistiquée, appelée star-merge, qui permet de fusionner successivement les mêmes branches sans se poser de question.

Vous pouvez utiliser svk smerge entre deux dépôts comme nous venons de le voir mais aussi entre un dépôt et une copie de travail en spécifiant le chemin de votre copie de travail en seconde position comme ceci :

  % svk smerge -Il //local/monprojet/branches/monprojet-1.0 \
    /ma/copie/de/travail

Fusionner seulement quelques révisions

Aussi parfois appelé « cherry picking » (cueillette de cerise).

Imaginons maintenant le cas inverse, vous développez dans trunk et trouvez des bugs. Après correction vous aimeriez bien les reporter dans votre branche monprojet-1.0. Seul problème, vous avez aussi fait des modifications substantielles dans d’autres parties de trunk que vous ne voulez pas voir apparaître dans la branche.

smerge ne sait pas faire ça, il va falloir se rabattre sur la commande merge.

Avant toute chose on va chercher les révisions que l’on veut fusionner dans notre branche, la commande log va nous trouver ça :

  % 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

Le bug a été corrigé dans la révision 15, nous pouvons vérifier la correction de bug en faisant un diff :

  % 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'

C’est bien cette correction de bug que nous voulons fusionner. Nous pouvons donc appliquer le patch. Nous pouvons l’appliquer soit directement sur le dépôt (comme vu avec smerge), soit en se plaçant directement dans un répertoire de travail contenant notre branche et en faisant :

  % svk merge  -r 14:15 //local/monlogiciel/trunk/
  U   generate

Il vous faudra alors commiter ces modifications.

L’avantage de faire la fusion directement sur le dépôt est que vous n’aurez pas à faire le commit ensuite.

Cette partie suppose que vos commits forment un tout homogène. Un commit pour les corrections de bug, un commit pour l’ajout de tel fonctionnalité, etc.

Gérer des modifications locales dans un logiciel

Nous allons étudier un cas relativement classique : vous utilisez un logiciel que vous avez adapté à votre environnement. À chaque nouvelle version vous devez réintégrer vos modifications à la main ce qui est long, fastidieux et contrevient clairement à une des vertus cardinales de l’informaticien, la paresse. SVK peut vous aider.

Travailler en mode déconnecté

Un des gros problèmes rencontrés quand vous utilisez un dépôt sur Internet est comment travailler quand vous n’avez pas accès à Internet pendant quelque temps. Vous pouvez revenir aux (pas si) bonnes vieilles méthodes, à savoir copier vos fichiers modifiés avec une extension précisant la date de modification ou la modification, et vous retrouvez rapidement avec des répertoires comme celui-ci :

  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 propose une solution simple et esthétique, un dépôt déconnecté. Pour faire cela il faut utiliser la notion de miroir.

  % svk mirror https://rubyforge.org/var/svn/redmine/ //mirror/redmine
  % svk sync //mirror/redmine

La première commande va créer le miroir, la seconde va importer toutes les données du dépôt distant dans votre miroir. Quand vous faites un checkout directement depuis un serveur Subversion, c’est en fait ce que svk fait dans votre dos (rappelez-vous les questions qu’il vous a posées au début de ce tutoriel).

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

À partir de ce moment, vous pouvez faire un checkout de votre projet et commencer à travailler dessus hors-ligne en commitant régulièrement vos modifications.

Oui, mais si c’est en mode hors-ligne, comment répliquer vos modifications sur le dépôt central et récupérer les dernières modifications du dépôt central ? En utilisant les commandes svk push et svk pull.

Vous revenez de deux semaines sans accès à Internet, vous avez commité de nombreuses modifications et vous voudriez bien que vos petits collègues en profitent. Commencez par récupérer leurs modifications :

  % svk pull

Cette commande va d’abord mettre à jour votre miroir et ensuite faire un update de votre répertoire de travail. Vous aurez peut-être des conflits à résoudre. Une fois ces conflits résolus et commités, vous pouvez leur envoyer vos modifications :

  % svk push

Ces commandes sont en fait des habillages un peu plus sexy d’autres commandes, mais ne vous préoccupez pas trop de ça si vous n’en avez pas besoin. Et si vous en avez besoin, lisez le SVK Book.

Vous pouvez voir les modifications en attente d’être poussées en utilisant la commande diff comme ceci :

  % svk diff //mirror/monprojet/ //local/monprojet/

Proposer des modifications quand vous n’avez pas les droits d’écriture sur le dépôt

Il n’est pas rare de proposer des patchs sur des projets pour lesquels vous n’avez pas les droits d’écriture sur le dépôt. Vous pouvez bien sûr utiliser la commande diff présente sur votre système ou bien la commande diff de SVK mais ce dernier vous permet de faire mieux avec l’option --patch utilisable avec commit, push et smerge.

Pour l’utiliser, commitez vos modifications normalement dans votre dépôt local et ensuite utilisez push avec l’option --patch :

  % 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:

Quand votre correspondant recevra le fichier de patch il n’aura qu’a le déposer dans son fichier ~/.svk/patch et le rejouer en faisant :

  % svk patch apply svk_correction_bug

Répliquer un dépôt local sur un dépôt distant

Ça y est, votre logiciel est prêt à affronter la critique de vos contemporains et vous voudriez leur donner accès aux sources. Vous avez juste deux problèmes : votre dépôt est sur votre disque et vous ne voulez pas donner accès à tous vos projets. La solution, répliquer votre projet sur un autre serveur SVN, par exemple sur une forge sur internet.

Pour cette recette, vous avez normalement besoin d’un serveur svn extérieur mais nous allons contourner le problème en créant un autre dépot local.

D’abord, un petit mot sur les dépôts. Au début de cet article nous en avons créé un en faisant svk depotmap --init. Cette commande créé un dépôt par défaut que l’on peut ensuite utilisé en utilisant //. Même si cette possibilité est rarement utile et n’est pas forcément recommandée, SVK peut gérer plusieurs dépôts.

Créons donc ce second dépôt nommé « remote » dans le répertoire /tmp/remote (chemin pas forcément judicieux si vous comptez faire plus qu’un test…)

  % 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

Ce nouveau dépôt est accessible en préfixant les chemins par /remote/ à la place de // mais nous allons l’utiliser comme si c’était un dépôt distant et commencer par créer un miroir dans le dépôt par défaut :

  % 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

L’option baseless indique que svk doit faire le smerge même si les deux projets n’ont pas de racine commune et incremental que chaque changement doit être appliqué individuellement.

Ça y est le miroir est fait. Vous aurez juste à penser à mettre à jour votre dépôt externe en lançant de temps en temps la commande :

  % svk smerge --incremental -m "mise a jour" //local/monprojet/ \
     //mirror/remote/monprojet/

Malheureusement vous ne pourrez pas utiliser la commande svk push pour mettre à jour cette copie. À ce niveau, plusieurs solutions s’offre à vous :

Métadonnées ou propriétés

Les métadonnées sont des données servant à décrire ou à ajouter de l’information à d’autres données. Dans un système de fichiers, les droits du fichier sont un exemple de métadonnées, ils ne font pas partie du fichier mais servent à ajouter une information à ce fichier.

SVK (ainsi que Subversion) appelle ces métadonnées des « propriétés ». Ces propriétés sont manipulables avec les commandes proplist, propget, propset, propedit et propdel qui respectivement, liste toutes les propriétés et retourne, modifie, lance un éditeur pour modifier et enfin supprime une propriété. Voyons un exemple :

  % 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

Les propriétés sont représentées par un nom et une valeur. Ces propriétés sont versionnées exactement comme le fichier. Vous pouvez faire dessus des commit, des revert et toutes les opérations classiques. Elles seront également accessible à toutes les personnes utilisant SVK ou Subversion pour travailler sur votre projet.

Si vous faites un svk diff sur un fichier auquel vous avez ajouté une propriété, vous verrez quelque chose comme :

  % svk diff README 

  Property changes on: README
  ___________________________________________________________________
  Name: copyright
   +NBC 2007

Voici un certain nombre de propriétés utiles :

  • svn:executable

    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.

  • svn:eol-style

    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.

  • svn:ignore

    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.

Configuration de SVK

Comme nous l’avons déjà vu, SVK s’appuie sur Subversion pour la partie système de fichiers et pour la gestion des propriétés. Il s’appuie également dessus pour la partie configuration. Le fichier utilisé pour le configurer est ~/.subversion/config. Par défaut il est entièrement commenté.

Nous avons vu un peu plus haut (dans la section parlant de la commande add) que SVK ignorait certains fichiers. Cette liste est évidemment paramétrable. Pour cela, ajoutez dans le fichier de configuration :

  [miscellany]
  global-ignores = *.o *.lo *.la #*# .*.rej *.rej .*~ *~ .#* .DS_Store

Une deuxième configuration potentiellement intéressante est de fixer automatiquement les propriétés des fichiers suivants leur extension :

  [miscellany]
  enable-auto-props = yes
  [auto-props]
  *.rb = svn:eol-style=native
  *.pl = svn:eol-style=native
  *.png = svn:mime-type=image/png
  ...

À ma connaissance, ce sont les deux seules configurations possibles dans SVK. Ceci dit, l’information étant difficile à trouver en dehors du code source, j’ai pu en louper certaines.

Éléments de méthode de travail

Cette partie n’essaye pas de proposer une méthode de travail générique, elle donne juste quelques pistes pour travailler le mieux possible avec SVK. Elle s’applique sans doute à beaucoup d’autres outils de gestion de versions.

Voici un diagramme récapitulant les flux des commandes importantes de SVK :

SVK version 2

Pour écrire cet article je me suis appuyé sur la version 1 mais le développement est très actif et la version 2 est sortie le 28 décembre 2006. Elle apporte, en plus des corrections de bogues, plusieurs fonctionnalités dont certaines sont vraiment très intéressantes comme :

  • les commits interactifs

    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 ;

  • l’amélioration de la sortie des journaux

    Vous pouvez maintenant y appliquer des filtres (recherche par exemple) et modifier la sortie (standard, XML, …) ;

  • l’apparition des vues

    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à.

Quelques idées en l’air

Si les outils de gestion de versions sont généralement utilisés pour gérer les sources d’un programme, il serait dommage de les limiter à cela. Ils peuvent être détournés pour faire plein de choses intéressantes et SVK a certains atouts non négligeables à détourner :

Comme vous le voyez, les possibilités sont larges.

Les liens