Modèles courants de gestion des branches

Il existe de nombreux usages pour la création et la fusion des branches ; ce paragraphe décrit les plus courants.

Le plus souvent, la gestion de versions est utilisée pour le développement de logiciels, voici donc un coup d'œil rapide à deux des modèles les plus courants de création et de fusion de branches utilisés par les équipes de programmeurs. Si vous ne vous servez pas de Subversion pour développer des logiciels, n'hésitez pas à sauter ce paragraphe. Si vous êtes un développeur de logiciels qui utilise la gestion de versions pour la première fois, soyez très attentifs, car ces modèles sont souvent considérés comme des bonnes pratiques par les développeurs plus expérimentés. Ces procédures ne sont pas spécifiques à Subversion ; elles sont applicables à tout système de gestion de versions. Néanmoins, les voir explicitées en termes Subversion peut aider.

Branches de publication

En général un logiciel suit un cycle de vie classique, répétant les trois étapes suivantes en boucle : code, test, publication. Il y a deux problèmes avec ce processus. Premièrement, les développeurs doivent continuer à écrire de nouvelles fonctionnalités pendant que les équipes d'assurance qualité prennent le temps de tester des versions supposées stables du logiciel. Les nouveaux développements ne peuvent pas s'arrêter pendant que le logiciel est en cours de test. Deuxièmement, l'équipe doit presque toujours effectuer le support des versions anciennes et publiées du logiciel ; si un bogue est découvert dans le code le plus récent, il existe probablement aussi dans les versions qui ont été publiées et les clients voudront obtenir le correctif pour ce bogue sans avoir à attendre la publication d'une nouvelle version majeure.

C'est là où la gestion de versions peut s'avérer utile. La procédure standard ressemble à ceci :

  1. Les développeurs propagent tout nouveau travail vers le tronc. Les modifications quotidiennes sont propagées vers /trunk : nouvelles fonctionnalités, corrections de bogues, etc.

  2. Le tronc est copié vers une branche « de publication ». Lorsque l'équipe estime que le logiciel est prêt à être publié (disons en version 1.0), /trunk peut être copié vers /branches/1.0.

  3. Les équipes continuent à travailler en parallèle. Une équipe commence à tester rigoureusement la branche de publication, pendant qu'une autre équipe continue avec les nouvelles tâches (disons pour la version 2.0) sur /trunk. Si des bogues sont découverts dans l'un ou l'autre des emplacements, les correctifs sont reportés de l'un à l'autre selon les besoins. Il arrive cependant un moment où même ce processus s'arrête. La branche est « gelée » pour les tous derniers tests juste avant publication.

  4. La branche est étiquetée et publiée. Quand les tests sont terminés, /branches/1.0 est copiée vers /tags/1.0.0 en tant que cliché de référence. L'étiquette est exportée et livrée aux clients.

  5. La branche est gérée au fil du temps. Pendant que le travail continue sur /trunk en vue de la version 2.0, les correctifs de bogues continuent à être reportés de /trunk à /branches/1.0. Lorsque suffisamment de correctifs se sont accumulés, les responsables peuvent décider de publier une version 1.0.1 : /branches/1.0 est copiée vers /tags/1.0.1 et cette étiquette est exportée et publiée.

Ce processus entier se répète au fur et à mesure que le logiciel gagne en maturité : quand le travail pour la version 2.0 est terminé, une nouvelle branche de publication 2.0 est créée, testée, étiquetée et finalement publiée. Au bout de quelques années, le dépôt finit par avoir un certain nombre de branches de publication en mode « maintenance » et un certain nombre d'étiquettes représentant les versions finales publiées.

Branches fonctionnelles

Une branche fonctionnelle est la sorte de branche qui est l'exemple dominant dans ce chapitre (celle sur laquelle vous travailliez pendant que Sally continuait à travailler sur /trunk). C'est une branche temporaire créée pour travailler sur un changement complexe sans interférer avec la stabilité de /trunk. À la différence des branches de publication (dont le support doit parfois être prolongé très longtemps), les branches fonctionnelles naissent, sont utilisées pendant un temps, sont fusionnées vers le tronc et sont finalement supprimées. Elles ont une utilité limitée dans le temps.

Encore une fois, les stratégies varient énormément au sujet du moment approprié pour créer une branche fonctionnelle. Certains projets n'utilisent jamais de branche fonctionnelle : n'importe qui peut propager des modifications à /trunk. L'avantage de ce système est qu'il est simple : personne n'a besoin d'être formé aux branches ou aux fusions. L'inconvénient est que le code du tronc est souvent instable ou inutilisable. D'autres projets utilisent les branches à l'extrême : une modification n'est jamais propagée directement dans le tronc. Même les modifications les plus triviales sont faites au sein d'une branche à courte durée de vie, vérifiées attentivement, puis fusionnées vers le tronc. La branche est ensuite supprimée. Ce système garantit que le tronc restera exceptionnellement stable et utilisable à tout moment, mais aux dépens des coûts de gestion liés à cette procédure très lourde.

La plupart des projets choisissent une approche à mi-chemin entre les deux. Ils insistent généralement pour qu'à tout moment /trunk puisse être compilé et passe avec succès les tests de régression. Une branche fonctionnelle n'est nécessaire que quand une modification nécessite un grand nombre de propagations susceptibles de déstabiliser le tronc. Une bonne méthode empirique est de se poser la question suivante : si le développeur travaillait pendant plusieurs jours en isolation et ensuite propageait cette grosse modification en une seule fois (afin que /trunk ne soit jamais déstabilisé), est-ce que ce serait une modification trop grosse à vérifier ? Si la réponse à cette question est « oui », alors la modification devrait être développée sur une branche fonctionnelle. Au fur et à mesure que le développeur propage ses modifications incrémentales dans la branche, elles peuvent facilement être vérifiées par ses pairs.

Finalement, il reste la question de savoir quelle est la meilleure méthode pour garder une branche synchronisée avec le tronc au fur et à mesure que le travail avance. Comme nous l'avons mentionné précédemment, il est très risqué de travailler sur une branche pendant des semaines ou des mois ; le tronc continuera peut-être à recevoir des modifications, au point que les deux lignes de développement risquent de s'éloigner tellement l'une de l'autre qu'essayer de fusionner la branche vers le tronc devienne un cauchemar.

Le mieux pour éviter une telle situation est de fusionner régulièrement les modifications du tronc vers la branche. Faites-en une habitude : une fois par semaine, fusionnez les modifications du tronc de la semaine précédente vers la branche.

Le moment arrivera où vous serez prêt à fusionner la branche fonctionnelle « synchronisée » vers le tronc. Commencez donc par effectuer une dernière fusion des modifications les plus récentes du tronc vers la branche. Une fois que c'est fait, les dernières versions de la branche et du tronc sont absolument identiques, mises à part vos propres modifications sur la branche. Vous êtes alors en mesure de fusionner la branche vers le tronc avec l'option --reintegrate :

$ cd copie-de-travail-du-tronc

$ svn update
À la révision 1910.

$ svn merge --reintegrate http://svn.exemple.com/depot/calc/branches/ma-branche
--- Fusion des différences des URLs du dépôt vers '.':
U    reel.c
U    entier.c
A    nouveau-dossier
A    nouveau-dossier/nouveau-fichier
 U   .
…

Une autre façon de concevoir ce modèle est d'imaginer que votre synchronisation hebdomadaire du tronc vers la branche est analogue au lancement de svn update dans une copie de travail, tandis que l'étape finale de fusion est analogue au lancement de svn commit depuis une copie de travail. Après tout, une copie de travail n'est rien d'autre qu'une branche privée très superficielle : c'est une branche qui n'est capable de ne contenir qu'une modification à la fois.