This text is a work in progress—highly subject to change—and may not accurately describe any released version of the Apache™ Subversion® software. Bookmarking or otherwise referring others to this page is probably not such a smart idea. Please visit http://www.svnbook.com/ for stable versions of this book.
Jusqu'à présent, nous nous sommes occupés des conflits intéressant le contenu des fichiers. Quand vos collaborateurs et vous faites des changements qui interfèrent dans le même fichier, Subversion vous force à fusionner ces changements avant de pouvoir les propager. [9]
Mais que se passe-t-il si vos collaborateurs déplacent ou suppriment un fichier sur lequel vous êtes en train de travailler ? À la suite d'un malentendu, quelqu'un a pensé que le fichier devait être supprimé alors qu'un autre veut toujours propager des modifications sur le fichier. Ou à l'occasion d'un réusinage de code, des collaborateurs ont renommé des fichiers et déplacé des dossiers. Si vous travailliez toujours sur ces fichiers, les modifications devront sûrement s'appliquer aux fichiers à leurs nouveaux emplacements. Ces conflits, qui se manifestent au niveau de la structure des dossiers plutôt que dans le contenu des fichiers eux-mêmes, portent le nom de conflits d'arborescences.
Comme pour les conflits textuels, les conflits d'arborescences empêchent la propagation d'avoir lieu en l'état, donnant l'opportunité à l'utilisateur d'examiner les conflits qui se présentent dans la copie de travail et de les résoudre avant de réaliser la propagation.
Prenons l'exemple d'un projet logiciel sur lequel vous travaillez et qui ressemble à ceci :
$ svn list -Rv svn://svn.exemple.com/trunk/ 13 harry 06 sept., 10:34 ./ 13 harry 27 06 sept., 10:34 COPYING 13 harry 41 06 sept., 10:32 Makefile 13 harry 53 06 sept., 10:34 LISEZMOI 13 harry 06 sept., 10:32 code/ 13 harry 54 06 sept., 10:32 code/machin.c 13 harry 130 06 sept., 10:32 code/truc.c $
Plus tard, lors de la révision 14, votre collaborateur
Harry renomme le fichier machin.c
en
bidule.c
. Malheureusement, vous n'y
prêtez pas attention toute de suite. Vous êtes occupé à
réaliser un ensemble de modifications différent, dont
certaines concernent machin.c
:
$ svn diff Index: code/truc.c =================================================================== --- code/truc.c (revision 13) +++ code/truc.c (copie de travail) @@ -3,5 +3,5 @@ int main(int argc, char *argv[]) { printf("Je n'aime pas être baladé !\n%s", machin()); - return 0; + return 1; } Index: code/machin.c =================================================================== --- code/machin.c (revision 13) +++ code/machin.c (copie de travail) @@ -1,4 +1,4 @@ const char *machin(void) { - return "Moi non plus !\n"; + return "Bah, moi j'aime bien être ballotté !\n"; } $
Vous commencez à réaliser que quelqu'un a modifié
machin.c
quand votre tentative de
propagation échoue :
$ svn commit -m "Quelques petits changements." Envoi code/machin.c Transmission des données . svn: E155011: Échec de la propagation (commit), détails : svn: E155011: Fichier '/home/svn/projet/code/machin.c' obsolète svn: E160013: Fichier non trouvé : transaction '14-e', chemin '/code/machin.c' $
À ce moment, vous devez lancer svn update.Non seulement votre copie de travail est mise à jour et vous pouvez voir les modifications effectuées par Harry, mais aussi l'arborescence est marquée comme étant en conflit afin que vous puissiez réellement mesurer ce qui a été modifié et résoudre le conflit proprement.
$ svn update Mise à jour de '.' : C code/machin.c A code/bidule.c U Makefile Actualisé à la révision 14. Résumé des conflits : Arborescences en conflit : 1
Dans la sortie qu'elle produit, svn update indique un conflit d'arborescence en utilisant un C majuscule dans la quatrième colonne. svn status fournit plus de détails sur ce conflit :
$ svn status M code/truc.c A + C code/machin.c > local edit, incoming delete upon update Résumé des conflits : Arborescences en conflit : 1 $
Notez que machin.c
est automatiquement
marqué pour ajout dans votre copie de travail, ce qui simplifie
les choses si vous décidez de conserver le fichier.
Du fait qu'un déplacement dans Subversion est implémenté comme une copie suivie d'un effacement et que ces deux opérations ne peuvent pas être corrélées facilement lors d'une mise à jour, tout ce que Subversion peut vous dire c'est que la mise à jour va effacer le fichier sur lequel vous avez fait des modifications. L'effacement peut faire partie d'un déplacement ou n'être simplement qu'un effacement en tant que tel. Déterminer exactement quelle est la sémantique associée à cette modification dans le dépôt est important : vous devez savoir dans quelle mesure vos modifications s'intègrent dans l'évolution générale du projet. Lisez donc les commentaires de propagation, discutez avec vos collaborateurs, étudiez les lignes modifiées à l'aide de la visualisation « diff ». Bref, faites ce que vous avez à faire pour déterminer quelle est la conduite à tenir dans ce cas précis.
Ici, le commentaire de propagation de Harry vous donne toutes les informations utiles.
$ svn log -r14 ^/trunk ------------------------------------------------------------------------ r14 | harry | 2011-09-06 10:38:17 -0400 (dim. 06. sept. 2011) | 1 ligne Chemins modifiés: M /Makefile D /code/machin.c A /code/bidule.c (de /code/machin.c:13) J'ai renommé machin.c en bidule.c et modifié le Makefile en conséquence. ------------------------------------------------------------------------ $
svn info affiche les URL des éléments en conflit. L'URL de gauche indique la source locale du conflit alors que l'URL droite indique la source externe du conflit. Ces URL vous montrent où vous devez commencer à chercher les modifications qui génèrent le conflit dans l'historique du dépôt.
$ svn info code/machin.c Chemin: code/machin.c Nom: machin.c URL: http://svn.exemple.com/svn/depot/trunk/code/machin.c … Tree conflict: local edit, incoming delete upon update Source gauche: (fichier) ^/trunk/code/machin.c@4 Source droit: (aucun) ^/trunk/code/machin.c@5 $
On dit que machin.c
est victime du
conflit d'arborescence. Il ne peut pas être propagé tant que
le conflit n'est pas résolu :
$ svn commit -m "Petites résolutions de problèmes" svn: E155015: Échec de la propagation (commit), détails : svn: E155015: Arrêt de la propagation : '/home/svn/projet/code/machin.c' demeure en conflit $
Pour résoudre ce conflit, vous devez soit approuver soit rejeter le déplacement effectué par Harry.
Si vous approuvez le déplacement, votre
machin.c
est superflu. Vous pouvez alors
l'effacer et marquer le conflit comme résolu. Mais
attendez : vous avez effectué des modifications dans ce
fichier ! Avant d'effacer machin.c
,
vous devez décider si les modifications que vous avez
effectuées doivent être appliquées ailleurs, par exemple
dans le nouveau fichier bidule.c
, qui
contient en effet tout l'ancien code de
machin.c
. Considérons que vos
modifications doivent « suivre le mouvement ».
Subversion n'est pas assez perfectionné pour faire ce travail
à votre place[10], vous devez donc faire ces
modifications manuellement.
Dans notre exemple, vous pourriez manuellement refaire vos
modifications sur machin.c
assez
facilement — ce n'était qu'un seul changement de ligne
après tout. Cependant, ce n'est pas toujours le cas, c'est
pourquoi nous allons voir une approche qui peut s'appliquer sur
de plus gros changements. Nous commencerons par utiliser
svn diff pour générer un fichier patch.
Ensuite, nous allons modifier les entêtes de ce fichier patch
pour pointer vers le nouveau nom de notre fichier déplacé.
Finalement, nous appliquons à nouveau le fichier patch modifié
sur la copie de travail.
$ svn diff code/machin.c > FICHIER_CORRECTIF $ cat FICHIER_CORRECTIF Index: code/machin.c =================================================================== --- code/machin.c (révision 14) +++ code/machin.c (copie de travail) @@ -1,4 +1,4 @@ const char *machin(void) { - return "Moi non plus!\n"; + return "Bah, moi j'aime bien être ballotté !\n"; } $ ### Editer FICHIER_CORRECTIF pour pointer vers code/bidule.c au lieu de code/machin.c $ cat FICHIER_CORRECTIF Index: code/bidule.c =================================================================== --- code/bidule.c (révision 14) +++ code/bidule.c (copie de travail) @@ -1,4 +1,4 @@ const char *machin(void) { - return "Moi non plus!\n"; + return "Bah, moi j'aime bien être ballotté !\n"; } $ svn patch FICHIER_CORRECTIF U code/bidule.c $
Maintenant que les changements que vous aviez faits
originellement sur machin.c
ont été
correctement reproduits dans bidule.c
, vous
pouvez effacer machin.c
et résoudre le
conflit en indiquant que vous choisissez la version de la copie
de travail comme valide.
$ svn delete --force code/machin.c D code/machin.c $ svn resolve --accept=working code/machin.c Conflit sur 'code/machin.c' résolu $ svn status M code/bidule.c M code/truc.c $ svn diff Index: code/truc.c =================================================================== --- code/truc.c (revision 14) +++ code/truc.c (working copy) @@ -3,5 +3,5 @@ int main(int argc, char *argv[]) { printf("Je n'aime pas être baladé !\n%s", machin()); - return 0; + return 1; } Index: code/bidule.c =================================================================== --- code/bidule.c (revision 14) +++ code/bidule.c (working copy) @@ -1,4 +1,4 @@ const char *machin(void) { - return "Moi non plus!\n"; + return "Bah, moi j'aime bien être ballotté !\n"; } $
Mais que se passe-t-il si vous n'êtes pas d'accord avec le
déplacement ? Eh bien, dans ce cas, vous pouvez effacer
bidule.c
après vous être assuré que
celui-ci ne contient pas de modification postérieure à son
renommage que vous souhaiteriez conserver (n'oubliez pas non
plus de revenir sur les modifications effectuées par Harry sur
Makefile
). Comme
machin.c
est déjà prévu d'être ajouté
lors de la prochaine propagation, il n'y a rien de plus à
faire et le conflit peut être marqué comme résolu :
$ svn delete --force code/bidule.c D code/bidule.c $ svn resolve --accept=working code/machin.c Conflit sur 'code/machin.c' résolu $ svn status M code/truc.c A + code/machin.c D code/bidule.c M Makefile $ svn diff Index: code/truc.c =================================================================== --- code/truc.c (revision 14) +++ code/truc.c (copie de travail) @@ -3,5 +3,5 @@ int main(int argc, char *argv[]) { printf("Je n'aime pas être baladé !\n%s", machin()); - return 0; + return 1; } Index: code/machin.c =================================================================== --- code/machin.c (revision 14) +++ code/machin.c (copie de travail) @@ -1,4 +1,4 @@ const char *machin(void) { - return "Moi non plus!\n"; + return "Bah, moi j'aime bien être ballotté !\n"; } Index: code/bidule.c =================================================================== --- code/bidule.c (revision 14) +++ code/bidule.c (copie de travail) @@ -1,4 +0,0 @@ -const char *machin(void) -{ - return "Moi non plus!\n"; -} Index: Makefile =================================================================== --- Makefile (revision 14) +++ Makefile (copie de travail) @@ -1,2 +1,2 @@ truc: - $(CC) -o $@ code/truc.c code/bidule.c + $(CC) -o $@ code/truc.c code/machin.c
Vous avez résolu votre premier conflit d'arborescence. Vous pouvez propager vos modifications et vous plaindre auprès de Harry à la pause café à propos de la surcharge de travail qu'il vous a infligée.
[9] Certes, vous pouvez simplement marquer les fichiers en conflits comme résolus et les propager, si vous le voulez vraiment. Mais c'est rarement le cas en pratique.
[10] Dans certains cas, il arrive que Subversion 1.5 ou 1.6 fasse le transfert pour vous, mais cette fonctionnalité un peu « ça passe ou ça casse » a été enlevée dans Subversion 1.7.