Création d’un dépot local (repository) SVN

  1. Créez un dossier dédié au présent TP. Nous ne nommerons svn dans la suite de l’énoncée.

  2. Dans ce dossier, créez-en un nommé client et un autre nommé serveur. Dans un terminal, positionnez vous sur le dossier serveur.

La plupart du temps, les serveurs sont abrités sur des machines différentes des clients. Dans le cadre de ce TP, nous travaillerons en local sur localhost et “simulerons” plusieurs clients se synchronisant avec le serveur.

A ce point, la commande tree -d devrait afficher

..
├── clients
└── serveur

Correction

$ mkdir svn
$ cd svn
$ mkdir serveur
$ mkdir clients
$ cd serveur
  1. Créez le dépôt SVN du projet 1 avec la commande
$ svnadmin create projet1

Vérifiez qu’un dossier projet1 a bien été créé. La commande tree -d lancée du dossier svn affiche quelque chose comme :

.
├── clients
├── init1
├── init2
└── serveur
    └── projet1
        ├── conf
        ├── db
        ├── hooks
        └── locks

On remarque ainsi que projet1 et projet2 – créés par svnadmin create – contiennent des dossiers qui seront employés par SVN pour la configuration et le stockage des différentes versions du projet.

  1. Éditez le fichier projet1/conf/passwd pour déterminer les utilisateurs pouvant accéder à ce dépôt SVN. Saisissez les informations suivantes :
[users]
usera = passa
userb = passb

Pour éditer le fichier, vous pouvez par exemple lancer la commande gedit projet1/conf/passwd ou bien nano projet1/conf/passwd.

Ce faisant, l’utilisateur avec le login usera pourra accéder au dépôt avec le mot de passe passa. Un autre utilisateur pourra également y accéder. Ces informations ne seront employées que lors d’un accès par le protocole svn://, et pas localement (dans ce cas, ce sont les droits du système de fichiers qui régissent les accès en lecture et écriture au dépôt).

  1. Créez un second depôt, pour un projet 2. Les utilisateurs userb et userc y auront accès.

Ainsi,

  1. Pour que ces mots de passe soient employés, il est également nécessaire de modifier les fichiers de configuration projet1/conf/svnserve.conf et projet2/conf/svnserve.conf en décommantant les lignes suivantes :
anon-access = read
auth-access = write
password-db = passwd
  1. Dans le cas où l’on met en place un accès distant, il est important de masquer les fichiers de mots de passe et d’autorisations (non employés dans ce TP).
$ chmod o-r projet1/conf/authz 
$ chmod o-r projet1/conf/passwd
$ chmod o-r projet2/conf/authz 
$ chmod o-r projet2/conf/passwd

Initialisation de dépôts (import)

Création des versions initiales des projets

  1. Dans le dossier svn, créez deux dossiers init1 et init2. Ces deux dossiers vont abriter les versions initiales des projets 1 et 2.

La commande tree -d svn lancée du dossier svn devrait afficher quelque chose comme :

.
├── clients
├── init1
├── init2
└── serveur
    ├── projet1
    └── projet2

(raccourci)

L’emplacement où sont créés init1 et inti2 est en fait indifférent. Ces dossiers ne serviront qu’à l’initialisation des dépôts.

  1. Dans le projet 1, créez un fichier prose.txt avec le contenu suivant :
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus hendrerit tempus consequat. Donec ut massa vitae lacus euismod luctus. Nunc venenatis auctor leo id facilisis. Etiam et lobortis quam. Aliquam erat volutpat. Quisque non eleifend eros. Nulla mauris sem, sodales ut massa quis, consequat mattis odio. Aliquam luctus, quam nec aliquam ornare, orci metus posuere sem, non tincidunt tellus enim ac massa. Curabitur rhoncus odio non congue volutpat.
  1. Dans le projet 2, crééz un fichier HelloWorld.java avec le contenu suivant :
class HelloWorld {

}

Initialisation d’un dépôt local

L’initialisation du projet 1 s’opère par l’importation du contenu de inti1 dans le dépôt SVN projet1. Comme le dépôt est sur le système de fichiers local, on peut employer le protocole file://.

  1. Importez la première version du projet (avec prose.txt) dans le dépôt projet 1 par la commande suivante, à supposer que l’on soit positionné dans le dossier svn.
svn import init1 file:///CHEMIN-VERS-SVN/svn/serveur/projet1 -m "création du projet1"

Vous devriez obtenir un message de confirmation de l’import :

Ajout          init1/prose.txt
Révision 1 propagée.

Utilisation du protocole svn:// pour des accès distants

Sur une machine accessible par son IP, on peut utiliser un protocole spécifique à SVN en démarrant un serveur adéquat, comme on démarre Apache pour le protocole http://.

  1. Pour lancer le serveur SVN et faire en sorte que le dossier serveur créé plus haut soit la racine des dépôts disponibles, employez la commande suivante.
& svnserve -d -r /CHEMIN-VERS-SVN/svn/serveur &

Un ps -aux | grep svnserve permet de faire apparaître le numéro de processus et de vérifier que le démon est bien lancé.

Désormais, le serveur sera accessible de manière distante par l’adresse svn://IP/NOMDEPOT.

  1. Pour importer init2 dans projet2, utilisez le protocole SVN en employant la commande
svn import --username userb --password passb init2 svn://localhost/projet2 -m "création du projet2"

Ici, une identification est nécessaire. Si vous n’en saisissez pas les informations dans la ligne de commande, elles vous seront demandées.

En principe, un message de confirmation devrait apparaître.

Ajout          init2/HelloWorld.java
Révision 1 propagée.

Suppression des fichiers initiaux

  1. Maintenant que les fichiers des projets ont été importés dans les dépôts, ils sont devenus inutiles. On peut donc les supprimer :
$ rm -rf init1 init2
svn
├── clients
└── serveur
    ├── projet1
    └── projet2

Création de copies de travail locales

Trois utilisateurs usera, userb et usera ont été définis. Avec le protocole svn://, ils peuvent accéder aux dépôts de manière distante. Dans le cadre de ce TP, nous emploierons ce protocole mais ferons tout de la même machine, en “simulant” ces trois utilisateurs.

  1. Créez des dossiers user-a, user-b et user-c dans le dossier client.
svn
├── clients
│   ├── user-a
│   ├── user-b
│   └── user-c
└── serveur

Ces dossiers pourraient tout aussi bien être n’importe où, sur des machines différentes et utilisées par des individus différents.

  1. Pour mieux “faire semblant”, créez trois onglets dans votre terminal : un pour chaque utilisateur. Dans chaque onglet, on se positionne dans le dossier user-X.

Pour créer des copies de travail locales depuis le serveur, il suffit d’utiliser la commande svn checkout en indiquant le dépôt du projet que l’on veut récupérer.

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR A (en sélectionnant l’onglet A).

  1. Exécutez la commande suivante.
$ svn checkout svn://localhost/projet1

Un message de confirmation apparaît :

A    projet1/prose.txt
Révision 1 extraite.

L’utilisateur B peut travailler sur les deux projets et l’utilisateur C peut travailler sur le projet 2 seulement.

  1. Créez les copies locales requises dans les dossiers user-b et user-a.

A l’issue de ces manipulations, vous devriez obtenir l’arborescence suivante :

clients
├── user-a
│   └── projet1
│       └── prose.txt
├── user-b
│   ├── projet1
│   │   └── prose.txt
│   └── projet2
│       └── HelloWorld.java
└── user-c
    └── projet2
        └── HelloWorld.java

Modification de fichiers

Deux utilisateurs travaillent donc sur chaque projet, et modifient leurs copies locales de manière tout à fait indépendante. Il est néanmoins nécessaire de garantir une cohérence de leurs copies locales.

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR C (en sélectionnant l’onglet C).

  1. Éditez HelloWorld.java en employant par exemple la commande gedit projet2/HelloWorld.java ou nano projet2/HelloWorld.java. Modifiez le fichier en ébauchant une méthode main() :
class HelloWorld {
    static void main() {
    }
}
  1. Propagez ces changements au dépôt du projet 1.
svn commit projet2 -m "ajout d'un main"

Un message de confirmation apparaît.

Envoi          projet2/HelloWorld.java
Transmission des données .
Révision 2 propagée.

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR B

  1. Le fichier HelloWorld.java a-t-il changé ?

  2. Mettez à jour la copie locale du projet 2 et vérifiez que le fichier a bien été mis à jour.

$ svn update projet2

Prise en compte de nouveaux fichiers par SVN

  1. Toujours du point de vue de l’utilisateur B, créez un fichier vers.txt dans le projet1. Son contenu est :
Sans ruse et sans détours, sans honte ni mensonge
Sans qu'un désir nous trompe, ou qu'un remords nous ronge

D'avoir une âme douce et mystiquement tendre
Et d'espérer, de croire et de toujours attendre

Comment roulent les cieux, et quel puissant génie
Des sphères dans leur cours entretient l'harmonie

Elle aime, et n'aime plus, et puis elle aime encore
Cent fois elle brûla mon coeur du feu qui me dévore

Quelquefois seulement quand mon âme est oppressée
Je sens en rythmes nombreux déborder ma pensée
  1. Propagez les changements de la copie locale au dépôt du projet 1 avec un commit.
svn commit projet1 -m "ajout d'un poème en vers"

Il n’y a aucun message de confirmation et un update du point de l’utilisateur A confirme que rien n’a changé. D’ailleurs, du point de vue de B, la commande svn status -vu projet1 indique le statut suivant pour la copie locale :

                 1        1 pierre       projet1/prose.txt
?                                        projet1/vers.txt
                 1        1 pierre       projet1
État par rapport à la révision      1

Le ? indique en fait que vers.txt n’est pas géré par SVN.

  1. Utilisez svn add de manière adéquate, pour que vers.txt soit désormais géré par SVN.

  2. Sans commit, rien n’est transféré au dépôt. Commitez donc.

Comme vous lancez une opération d’écriture dans le dépôt, une authentification peut être requise. Le cas échéant, identifiez-vous en tant que userb avec le mot de passe passb, tel que défini plus haut.

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR A

  1. Mettez-à jour votre copie locale.

Désormais, on a bien :

clients
├── user-a
│   └── projet1
│       ├── prose.txt
│       └── vers.txt
├── user-b
│   ├── projet1
│   │   ├── prose.txt
│   │   └── vers.txt
│   └── projet2
│       └── HelloWorld.java
└── user-c
    └── projet2
        └── HelloWorld.java

Manipulation de fichiers

Suppression

Pour supprimer un fichier d’un projet, il ne faut pas simplement le supprimer du système de fichiers. Comme il est géré par SVN, il est nécessaire d’utiliser une commande SVN.

  1. Toujours du point de vue de A, supprimez prose.txt grâce à la commande :
$ svn delete projet1/prose.txt

Le fichier est supprimé localement, et le prochain commit propagera ce changement au dépôt. On n’est pas obligé de propager chaque changement immédiatement : on attend même souvent la fin d’une journée de travail pour faire un commit entraînant de nombreuses modifications simultanées.

  1. Ici, modifions également dans la copie de travail le fichier vers.txt pour que son contenu devienne moins fleur bleue :
Le minuscule radiocompas du grand bateau me poursuivait

L'impératrice envieuse du dernier chlorure adorait tenir la main du caprice de femme terrible

La giboulée de la poulette m'obsédait

La fille du bibi rêvait du l'adorateur stérilisé 

Renommage

Comme pour la suppression, le renommage d’un fichier pris en charge par SVN se fait à l’aide de la commande svn :

$ svn rename projet1/vers.txt projet1/poesie.txt

Propagation de changements multiples

Le statut de la copie locale (svn status -vu projet1) indique que plusieurs changements ont été effectués et doivent être propagés au dépôt.

A  +             -        2 userb        projet1/poesie.txt
D                2        1 pierre       projet1/prose.txt
D                2        2 userb        projet1/vers.txt
                 2        2 userb        projet1
État par rapport à la révision      2
  1. Effectuez ces changements grâce à un commit.

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR B

  1. Procédez à une mise à jour de la copie de travail de B.
$ svn update projet1
Updating 'projet1':
D    projet1/vers.txt
D    projet1/prose.txt
A    projet1/poesie.txt
Actualisé à la révision 3.

Travail à plusieurs sur le même fichier

Pour plus de commodité quand on travaille sur un seul projet, on se place souvent dans le dossier de la copie de travail du projet en question. Ainsi, exécutez des commandes cd projet2 dans les onglets des utilisateurs B et C. Les commandes SVN sont ainsi raccourcies car on n’est plus contraints de préciser le projet.

Modification du même fichier sans conflit

  1. Toujours du point de vue de B, modifiez HelloWorld.java :
class HelloWorld {
    static void main(String[] args) {
    }
}

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR C

  1. L’utilisateur change également le fichier HelloWorld.java :
class HelloWorld {
    static void main() {
        System.out.println("Hello world");
    }
}
  1. L’utilisateur C commite.
$ svn commit -m "affichage dans le main"

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR B

  1. L’utilisateur B commite et rien ne va plus :
$ svn commit -m "ajout des paramètres du main"
Envoi          HelloWorld.java
Transmission des données .svn: E160028: Échec de la propagation (commit), détails :
svn: E160028: Fichier '/HelloWorld.java' obsolète

L’utilisateur B ne peut pas propager ses modifications sur le serveur, car elles avaient été opérées à partir d’une version qui n’est plus la version courante sur le serveur. Dans ce cas, il convient plutôt de mettre d’abord à jour la copie locale avec la dernière version. Cette lise à jour cherchera à préserver le travail de l’utilisateur B.

$ svn update
Updating '.':
G    HelloWorld.java
Actualisé à la révision 3.
  1. Affichez le fichier HelloWorld.java de B. Que remarquez-vous ?

  2. Propagez le fichier au serveur et à la copie de travail de l’utilisateur C.

Modification du même fichier avec conflit

Quand deux clients modifient la même ligne, en revanche, il est difficile de rassembler plusieurs versions.

Assurez-vous que les deux utilisateurs B et C disposent de la même copie de HelloWorld.java :

class HelloWorld {
    static void main(String[] args) {
        System.out.println("Hello world");
    }
}
  1. Toujours du point de vue de B, modifiez HelloWorld.java, et propagez les changements au dépôt :
class HelloWorld {
    static void main(String[] args) {
        System.out.println("Hola mundo");
    }
}

PLACEZ VOUS DU POINT DE VUE DE L’UTILISATEUR C

  1. Modifiez HelloWorld.java, et propagez les changements au dépôt :
class HelloWorld {
    static void main(String[] args) {
        System.out.println("Ciao mondo");
    }
}

Là encore, le commit ne peut pas se faire.

  1. Comme précédemment, essayez de fusionnez la version du dépôt et celle de la copie de travail de C.

Ca ne fonctionne pas (entrez p) car c’est la même ligne qui a été modifiée et il en résulte un conflit qui doit être résolu manuellement. Pour ce faire, la copie locale voit apparaître plusieurs versions du fichier :

  1. Tranchez en modifiant HelloWorld.java :
class HelloWorld {
    static void main(String[] args) {
        System.out.println("Ciao mundo");
    }
}
  1. Avant de propager au dépôt, il est nécessaitre d’indiquer que le conflit a été résolu manuellement :
$ svn resolved HelloWorld.java

Après propagation, le fichier HelloWorld.java a subi quelques modifications que l’on peut tracer grâce à la sous-commande log.

$ svn log HelloWorld.java 

Pour aller plus loin

Ce TP est une courte introduction à Subversion. Mais SVN prend toute sa mesure

On recommande un ouvrage gratuit par les développeurs de Subversion pour aller plus loin.

Dans le cadre de ce TP, nous avons choisi de n’aborder que la ligne de commande. En pratique, les IDE comme Eclipse intègrent subversion, de manière à proposer une interface plus conviviale et intégrée au contrôle de version des logiciels développés en équipe.


Module d’UML