Conflits
La première notion à assimiler dans cette sous-partie est celle de
conflits. D'après un dictionnaire, un conflit est un choc, une lutte, une rivalité. Eh bien dans Subversion, c'est exactement la même chose : il y a une rivalité entre les utilisateurs à propos des fichiers versionnés. Comment cela ?
me direz-vous. Comme ceci :
vous répondrai-je.
Supposons deux utilisateurs (Joe et Bobby) devant travailler en même temps sur un fichier
README, et que leurs modifications sur ce fichier soient prises en compte par SVN, on peut dès lors dresser le scénario suivant :
- Joe et Bobby font un checkout sur du dépôt et obtiennent à la révision 1 le fichier README ;
- ils commencent tous les deux à éditer le fichier ;
- Joe, content de lui, fait un commit avec ses modifications, le fichier est uploadé et la révision 2 est créée ;
- Bobby, une fois ses propres modifications terminées, va vouloir en faire un commit, sauf que là c'est le drame, un message d'erreur lui dit qu'il ne peut pas le faire !
Comment cela se fait-il ? Rappelez-vous, je vous avais dit qu'il était important de toujours avoir une copie locale à jour, or celle de Bobby ne l'était plus au moment de son hypothétique
commit : sa copie locale était encore à la révision 1 alors que le dépôt était à la révision 2. Par mesure de sécurité, Subversion bloquera le commit pour éviter qu'il ne détruise les modifications de Joe. Il y a conflit !
Mais alors, le travail du pauvre Bobby est réduit à néant ?
Que nenni ! Subversion propose plusieurs moyens de résoudre et prévenir les conflits, que nous allons étudier dans cette sous-partie.
Merging
Pour
résoudre un conflit, Subversion propose une solution de
merging, terme signifiant ici
mélange. Basiquement, cela consiste en un mélange des deux fichiers pour en obtenir un nouveau. Il y a deux types de
merging pour résoudre les conflits, les voici les voilà :
Merging "automatique"
Subversion étant un être doué d'intelligence, il est capable de réaliser certaines opérations tout seul comme un grand.
Reprenons notre exemple de conflit entre Joe et Bobby : ce dernier se retrouve comme un con avec son
commit défectueux, la première chose à faire est un
update, afin de mettre sa copie locale à jour. Pas de panique, cela ne supprimera pas ses modifications : SVN sait qu'il y a conflit, et va donc agir !
Le cas du
merging "automatique" est efficace lorsque les modifications effectuées par les deux utilisateurs ne se "recoupent" pas, par exemple s'ils ont modifié chacun deux parties distinctes du fichier. Dans ce cas, Subversion repère ce non-recoupement et peut mélanger intelligemment les deux fichier. Voici une mise en pratique avec un fichier contenant "Bonjour !" avant toute modification :
Citation : Joe (commit réussi)J'ajoute ce texte au dessus de bonjour...
Bonjour !
Citation : Bobby (commit foireux)Bonjour !
Moi, je veux ajouter du texte en dessous !
Je suis désolé des exemples totalement débiles et sans intérêt mais il faut que tout le monde comprenne !
Comme vous le voyez ici, les modifications de l'un n'annulent pas celles de l'autre, et elles peuvent être distinctement séparées. Donc lorsque Bobby fera son
update, SVN laissera le fichier README contenant :
Citation : Bobby (après l'update)Je rajoute ce texte au dessus de bonjour...
Bonjour !
Moi, je veux rajouter du texte en dessous !
Il suffit alors de faire son
commit du fichier créé par Subversion pour le réussir et créer la révision 3 !
Merging "manuel"
Il arrive parfois (même plutôt souvent) que les modifications effectuées par deux utilisateurs se recoupent, et dans ce cas Subversion ne peut pas prendre le risque d'effectuer lui-même le
merging. C'est donc à l'utilisateur responsable du conflit de le corriger lui-même ! Je vais reprendre l'exemple du book SVN qui est facile à comprendre.
Imaginez qu'un fichier versionné soit une liste de ce que deux collaborateurs veulent pour leurs sandwiches, voici ce fichier à la révision 1 :
Citation : Fichier à la révision 14 tranches de jambon
3 tomates
9 cornichons
Maintenant, imaginons que Joe aime la viande, et ajoute une tranche de jambon (il y en aura donc cinq), il
commit, et juste après Bobby (toujours malchanceux avec ses
commits), tente d'envoyer son
commit pour les deux tranches de jambon supplémentaires :
Code : Console | Sending sandwiches.txt
svn: Commit failed (details follow):
svn: Out of date: 'sandwiches.txt' in transaction '5-1' |
Il tente de faire son
update comme la dernière fois, sauf que là ça ne fonctionne pas, et voilà avec quoi il se retrouve dans sa copie locale :
Code : Console | sandwiches.txt sandwiches.txt.mine sandwiches.txt.r4 sandwiches.txt.r5 |
Décortiquons un peu cela !
sandwiches.txt.mine contient le fichier qu'il a tenté de
commiter,
sandwiches.txt.r4 contient le fichier à la révision précédente (avant tout changement donc) et
sandwiches.txt.r5 contient le fichier avec les modifications de Joe. Mais ce qui est intéressant est le fichier
sandwiches.txt, si on l'édite voilà ce qu'il y a dedans :
Code : Console | <<<<<<< .mine
6 tranches de jambon
=======
5 tranches de jambon
>>>>>>> .r5
3 tomates
9 cornichons |
Et c'est là que vous prenez votre tube d'aspirine et que vous commencez à pleurer ! Sans raison, parce que ce n'est vraiment pas compliqué... Il y a deux choses à retenir, la signification des signes qu'on peut résumer à cela :
Code : Console | <<<<<<< .mine
CE QUE J'AI MODIFIE
=======
CE QUE L'AUTRE A MODIFIE
>>>>>>> .rX |
Tout ce qu'il y a en dehors des signes est ce qui n'a pas été modifié. Il suffit ici de faire réfléchir un peu ses méninges : on sait qu'il y avait 4 tranches de jambon avant (le fichier
sandwiches.txt.r4 en témoigne), Joe en demande une de plus, moi deux. Un peu de maths, ça fait qu'il en faut trois de plus. On retire donc les marques en laissant la ligne, mais en mettant sept tranches de jambon.
Dans des cas réels liés à la programmation, résoudre des conflits peut s'avérer plus ardu que cela, c'est pourquoi on verra comment éviter les conflits !
Tout ce qu'il nous reste à faire est de déclarer le conflit comme résolu, puis à réaliser le
commit :
Code : Console | svn resolved sandwiches.txt
svn commit -m "Conflit résolu youhouh" |
La sortie devrait être :
Code : Console | Resolved conflicted state of 'sandwiches.txt'
Sending sandwiches.txt
Transmitting file data .
Committed revision 6. |
Le conflit a aussi été résolu, mais avec plus de peine.
Il va évidemment de soi que la résolution de conflit ne marche que pour des fichier ASCII. Il est strictement impossible de résoudre un conflit sur un fichier binaire (image, vidéo, etc.) ! D'où la nécessité d'une lecture assidue du prochain point.
Lock
Après avoir vu comment résoudre un conflit, j'espère vous avoir à vie dégouté de ces petites choses-là. Je vous ai déjà dit à plusieurs reprises dans ce tuto de faire des
updates régulières pour essayer d'être à jour le plus souvent possible, mais cela ne suffira pas toujours. Il ne s'agit pas seulement de prier pour qu'un conflit ne se produise pas, il faut également les empêcher. L'expression
mieux vaut prévenir que guérir prend ici tout son sens.
Bien sûr vous pourriez courir après vos collaborateurs pour leur dire que vous allez modifier ce fichier dans les prochaines heures, mais ce n'est ni pratique ni productif. Non, pour cela vous allez utiliser la fonction de
lock de Subversion.
En production, votre responsable de projet vous menacera sûrement de pratiques verre-pileuses si jamais vous n'appliquez pas un effort constant et complet sur la mise en place de locks. Et il aura raison !
Là le nom est explicite, il s'agira de
verrouiller un fichier pendant que vous l'utiliserez, pour être certain que personne ne sera en mesure de le modifier à son tour. Mais ici encore, l'adoption d'une routine, d'une procédure d'utilisation de Subversion est requise ! En effet, demander un
lock sur un fichier avant modification doit devenir une habitude ! Cela permet deux choses : d'abord d'obtenir le
lock, et donc que personne ne gâche notre boulot ; mais également de s'assurer que personne n'a pris de
lock sur ce fichier, et donc qu'on n'est pas sur le point de gâcher le boulot de quelqu'un.
Le
lock doit donc devenir une institution, que dis-je ? on doit vénérer le
lock. Le
lock est le patron, le
lock c'est la vie, répétez après moi !
Pour demander un
lock, entrez la commande suivante :
Code : Console
Ce qui donne :
Code : Console | 'sandwiches.txt' locked by user 'apognu'. |
À partir de ce moment, n'importe qui demandant un
lock sur ce fichier se verra gratifié d'un majestueux :
Code : Console | svn: warning: Path '/sandwiches.txt' is already locked by user 'apognu' in filesystem '/home/apognu/svn/repository/db' |
Il est à noter que demander un
lock sur un fichier situé dans une copie locale non à jour provoquera également un message d'erreur. Demander un
lock permet aussi de s'assurer de travailler sur une base saine.
Surtout, ne pas oublier de
déverrouiller le fichier une fois qu'on a fini de travailler dessus, grâce au sous-programme
unlock :
Code : Console | svn unlock sandwiches.txt |
Une fois compris le fait que le
lock est le Bien, et pris l'habitude d'en demander un chaque fois que l'on désire travailler sur un fichier, le risque de création de conflits est minime, voire inexistant. Et ça c'est réjouissant !