Inter-File Branching

Une méthode de représentation pratique des variantes

Christopher Seiwald
Perforce Software

[ English | Français ]

Avant-propos

Les systèmes contemporains de gestion de configuration logicielle (GCL) identifient les variantes dans le même espace de noms que les révisions. Les variantes (mises en œuvre de substitution d'un élément de configuration devant exister en parallèle) et les révisions (améliorations répétitives que prend chaque variante avec le temps) forment une arborescence bidimensionnelle de la version d'un élément de configuration. Un élément de configuration possède donc généralement deux noms : un qui nomme l'élément et un autre qui nomme la version. Cet article présente une autre approche où l'identification d'une variante est déplacée dans le nom de l'élément de configuration, ne laissant à l'espace de noms de la version qu'un jeu linéaire de révisions. Cette méthode ayant été réalisée dans un système de travail où les éléments de configuration sont les fichiers source d'un logiciel, elle s'appelle Inter-File Branching. Branching désigne la création de variantes, les fichiers représentent les éléments de configuration tandis que inter-file reflète le fait que les variantes sont des fichiers distincts.

1. Introduction

Cet article décrit un nouveau mécanisme de gestion des variantes de fichier. Il décrit tout d'abord les deux principales facettes de la méthode actuelle, à savoir la façon dont les variantes sont nommées et créées; il précise leurs restrictions au niveau pratique. Il explique ensuite comment une nouvelle approche appelée Inter-File Branching ne subit pas les mêmes restrictions et décrit ce nouveau mécanisme dans le détail. Il conclut enfin par certaines observations empiriques sur l'utilisation de la méthode Inter-File Branching.

2. Ramification de l'arborescence de la version

2.1. La version nomme la variante

Un fichier est généralement identifié par deux noms : le nom du fichier et le nom de la version du fichier. La version se décompose ensuite en deux types d'informations: le nom de la variante et le nom de la révision de la variante. La variante sélectionne une mise en œuvre possible qui existe en parallèle, tandis que la révision sélectionne une mise en œuvre d'une variante qui a évolué avec le temps [4]. Généralement, la première révision d'une nouvelle variante est en réalité une révision d'une autre variante; cela s'appelle un point de ramification. Jointes aux points de ramification, les variantes et leurs révisions forment une arborescence de la version, chaque variante représentant une branche de l'arborescence et chaque révision représentant un nœud sur cette branche.

Dans SCCS [5] et RCS [8] (et les quelques douzaines de systèmes construits sur ces outils), le nom des variantes (appelées en fait "branches") est représenté par des paires de chiffres. Le nom de la révision comprend une autre paire de chiffres. Le nom du "tronc" est vide. Par exemple, 1.2.2.1.1.3 représente la révision 1.3 de la variante 1.2.2.1, qui elle-même est la révision 2.1 de la variante 1.2, qui est elle-même la révision 1.2 du tronc. Bien évidemment, il peut être déconcertant pour les utilisateurs d'avoir à mémoriser la signification de ces chiffres. C'est pour cette raison que des noms symboliques sont souvent appliqués aux versions importantes.

Le produit ClearCase d'Atria [1] n'utilise pas de numéros de révision et présente un nom de version hiérarchique à l'utilisateur. Par exemple, main/release2/bugfix/3 représente la révision 3 de la branche "bugfix", qui est dérivée (à un point donné) de la branche "release2", qui elle-même est dérivée du tronc principal. Il est plus facile de mémoriser une telle structure de nom que le schéma de numérotation utilisé par SCCS, avec l'argument discutable que le point de ramification n'est pas explicitement nommé.

L'approche qui consiste à représenter les variantes au sein de l'espace de noms de la version présente quelques lacunes :

Deux hiérarchies. Chaque variante d'un fichier est identifiée par le produit de deux noms hiérarchiques, à savoir le nom du fichier et le nom de la variante. Bien qu'il s'agisse d'un point subjectif, le fait d'avoir des fichiers identifiés par deux hiérarchies peut empêcher les utilisateurs de visualiser les configurations. En théorie, les systèmes de GCL sont suffisamment fonctionnels pour permettre aux utilisateurs de ne pas réellement avoir besoin d'une telle commodité, mais en pratique, les ingénieurs qui travaillent avec des produits logiciels complexes et leurs multiples versions ont bien souvent besoin de comprendre la "silhouette" de l'arborescence de fichiers de leur produit.

Cette image peut devenir particulièrement obscure si des variantes sont créées à la demande. Un tel mécanisme conserve une mise à jour d'une version non pas comme une nouvelle version de la même variante, mais comme le première révision d'une nouvelle variante. Après un certain temps, de nombreux fichiers possèdent alors plusieurs variantes connexes, et des configurations importantes peuvent comporter des variantes nommées de façon différente pour chacun des fichiers.

Sémantique disparate. Le fait de disposer d'un espace de noms pour les fichiers et d'un autre pour les variantes de ces fichiers pose un dilemme à l'utilisateur de systèmes de GCL existants car ces deux espaces de noms sont pris en charge par une sémantique différente. En particulier, la prise en charge de la fusion de delta automatisée est normalement liée à l'espace de noms de la version: il est seulement possible de fusionner les deltas entre variantes. (Un delta est la modification qui fait passer d'une révision à la suivante.) Par ailleurs, l'utilisateur ne peut voir qu'une variante d'un fichier à la fois.

Par conséquent, si l'utilisateur prévoit de fusionner des deltas entre variantes, il doit s'agir des variantes d'un seul fichier. D'autre part, si l'utilisateur souhaite accéder aux deux variantes en même temps, celles-ci doivent être de fichiers différents. Il existe plusieurs exemples réels où cette combinaison non prise en charge est souhaitable: dans les systèmes client/serveur, où les mises en œuvre client et serveur d'une machine protocole sont semblables mais pas identiques; dans les systèmes à plusieurs plates-formes, où les fichiers propres au système d'exploitation sont semblables mais pas identiques; dans les systèmes migrant d'un langage de programmation à un autre, où la synchronisation des mises en œuvre C et C++ doit éventuellement être conservée pour le moment. Dans chacun de ces cas, les fichiers sont des variantes les uns des autres, mais dans la pratique courante, ils sont des fichiers distincts.

Centré sur la Mainline. La représentation de l'espace de noms de la version suppose qu'une variante est la branche principale d'où descendent toutes les autres. Cette vision centrée sur la Mainline est souvent applicable dans les phases précoces d'un projet logiciel unique, mais elle convient rarement à la structure des produits évolués existants (en particulier ceux qui ont débuté avec une mauvaise GCL). Ces produits sont susceptibles d'avoir plusieurs "lignes directrices" des mêmes fichiers source, avec un développement actif disparate sur chacun.

La gêne occasionnée par le développement de plusieurs variantes principales peut forcer les utilisateurs à configurer des référentiels distincts pour des fichiers qui seraient autrement des variantes dans le même référentiel. La fusion automatisée et la prise en charge du suivi autorisé par le système de GCL sont alors délaissées.

2.2. Création de variantes

La méthode couramment utilisée pour représenter les variantes est associée à la méthode couramment utilisée pour les créer : pour chaque fichier, l'utilisateur sélectionne une version existante et la désigne comme point de départ d'une nouvelle variante. Généralement, la version existante porte un nom symbolique, de sorte que l'utilisateur n'a pas à établir une liste de chaque variante et révision. La nouvelle variante porte elle aussi un nom symbolique afin de servir de référence.

Les utilisateurs parlent souvent de "branche" pour désigner l'ensemble des fichiers partageant un même nom de variante. Mais la création d'une variante ne prend pas en charge la sémantique d'un collectif: elle crée uniquement des variantes de fichiers existants, en aucun cas des fichiers pouvant être créés ultérieurement. Si les modifications apportées à une branche doivent être fusionnées dans une autre, les utilisateurs doivent effectuer une étape supplémentaire pour créer les nouvelles variantes de chaque nouveau fichier. Plus important encore, les informations utilisées pour créer les variantes n'étant rien de plus qu'une version marquée pour chaque fichier, il n'existe aucun moyen externe de dire si une variante correspondante doit être créée pour un nouveau fichier.

Pour résoudre ce problème, certains systèmes de GCL traitent les conteneurs comme des éléments de configuration et en créent également des variantes. Mais ce schéma peut entraîner une complexité considérable et ajouter à la confusion: outre la création d'un plus grand nombre d'espaces de noms qui entrent en jeu dans l'identification des versions distinctes, il ne parvient pas à automatiser la création d'une variante lorsqu'un nouveau fichier est créé.

3. Inter-File Branching

Inter-File Branching est une autre approche qui offre des avantages potentiels par rapport à la ramification de l'arborescence de la version. Le concept fondamental réside dans la création d'une variante conforme au processus de duplication sous UNIX: un nouveau fichier est créé, lié au fichier d'origine dans un contenu initial et un historique, mais avec un futur sans entrave.

Ce modèle ressemble à ce que les utilisateurs ne disposant pas d'une prise en charge de la GCL doivent généralement faire lorsqu'ils sont confrontés à la nécessité de créer des branches pour leur logiciel: ils copient les fichiers et se soucient de la fusion plus tard. La différence entre cette méthode primitive et Inter-File Branching est que cette dernière automatise la copie initiale et la fusion ultérieure. Inter-File Branching est par essence un processus d'extension de la prise en charge pratique des variantes (fusion des deltas et suivi de l'historique de fusion) pour couvrir des fichiers distincts.

Avec Inter-File Branching, les différentes variantes sont des fichiers portant des noms différents. Le nom de fichier se compose d'une part de ce qui est généralement considéré comme le nom du fichier, et d'autre part du nom de la variante, bien que le nom exact soit laissé à l'appréciation de l'utilisateur. Il est possible, par exemple, qu'un fichier/release2.1/database/src/btree.c soit une variante de /patch2.1.5/database/src/btree.c ou que /x/y/z soit une variante de /a/b/c/d.

Inter-File Branching repose sur une pratique bien connue : copier des éléments pour en faire des variantes. Les utilisateurs peuvent ainsi exprimer naturellement la relation entre une nouvelle variante et une ancienne en lui attribuant un nom semblable. Il arrive, par exemple, qu'un utilisateur se contente de copier un fichier foo.c dans foo.c.bak . Un autre exemple peut-être plus probant est lorsque l'utilisateur copie mainline/src/* dans bob/src/* . Les fichiers de Bob sont des variantes de la Mainline, et leur nom indique la relation qui les unit.

Si cette copie se produit avec le référentiel de GCL plutôt que dans l'espace de travail de l'utilisateur, l'utilisateur parvient aisément à visualiser l'espace de noms du référentiel. Inter-File Branching permet aux utilisateurs d'identifier par une gestion unique la variante d'un fichier, ce qui facilite la visualisation de la "silhouette" des configurations. Comme dans l'exemple précédent, Bob sait que la configuration qui décrit son travail est tout simplement ce "qui se trouve sous src/bob/* dans le référentiel".

En traitant les variantes comme des fichiers distincts, un système de GCL prenant en charge Inter-File Branching peut permettre une fusion et un suivi automatisés entre n'importe quelle paire de fichiers. La sémantique des variantes peut même s'appliquer post hoc à des fichiers qui n'étaient pas initialement liés entre eux. Par conséquent, il est possible de prendre deux fichiers (peut-être antérieurs au contrôle de la GCL) et de commencer à les traiter comme des variantes l'un de l'autre.

Avec Inter-File Branching, les variantes ont des noms différents. En fait, il n'est même pas nécessaire que les noms soient semblables. Cela permet de créer une variante de l'intégralité d'une configuration (par exemple, des variantes de tous les fichiers d'une configuration), en réorganisant complètement l'espace de noms dans le processus en nommant les nouvelles variantes dans le schéma de noms souhaité. Ceci peut s'avérer utile dans un grand nombre de situations, principalement lorsqu'un logiciel est ramifié dans un autre projet sous la forme d'un partage de code: il est fort possible que la copie du logiciel appartenant au nouveau projet soit "remodelée" pour répondre à ses besoins.

Inter-File Branching relie les variantes par l'intermédiaire de l'espace de noms des fichiers. Il est alors possible de relier des configurations entières en exprimant la relation des noms des fichiers qui la composent. Si l'expression de cette relation exploite une organisation naturelle du logiciel, elle peut être relativement compacte. Par exemple, pour dire que le code de Bob est une variante de la Mainline, le code est "bob/src/*est une variante de mainline/src/*". Cette expression relie non seulement les fichiers existants, mais également les fichiers qui peuvent être créés dans l'espace de noms.

L'espace de noms de la version ne contenant plus le nom de la variante, il peut être réduit à un jeu linéaire de numéros de révisions (commençant à 1) pour chaque fichier. Ceci signifie que les configurations importantes sont souvent situées au sommet (numéros les plus élevés, les plus récents) des révisions de fichier dans une partie donnée de l'espace de noms. Par exemple, les derniers travaux de Bob se situent au somment des révisions des fichiers nommés bob/src/*.

3.1. Algorithme Inter-File Branching

La sémantique qui prend en charge cette automatisation de la fusion découle de la situation suivante : prenant un fichier source ("source") donné, chacun ou tous ses deltas distincts peuvent être valablement fusionnés dans le contenu d'un fichier cible ("cible"). Ce qui inclut le delta initial qui mène un fichier d'un contenu vide à sa première révision. La caractéristique qui permet de distinguer le fichier source du fichier cible est le nom. L'utilisateur sélectionne une source, quelques sous-jeux de ses deltas, et la cible. La logique suivante est ensuite appliquée:

  • Si les deltas ne sont pas contigus, ils sont fractionnés en fragments distincts contigus et la logique restante est appliquée à chaque fragment séparément.
  • Si la cible n'existe pas, elle est créée à l'aide du contenu de la source au niveau de révision sélectionné le plus élevé. Ce procédé est communément appelé "ramification" ; démarrer une nouvelle variante avec des contenus identiques.
  • Si la cible existe, l'utilisateur doit fusionner le contenu actuel de la cible avec le contenu de la source à son niveau de révision sélectionné le plus élevé. Le résultat de cette fusion représentera alors le numéro de révision suivant de la cible. S'il est possible de trouver une révision de base convenable, la fusion peut alors être automatisée avec un algorithme de comparaison/fusion courant. La base des fusions automatisées est la révision de la source un niveau sous le niveau de révision sélectionné le plus bas. S'il s'agit de la première révision de la source, il n'existe alors aucune base, et l'utilisateur devra choisir de remplacer le contenu de la cible par celui de la source, de laisser la cible en l'état ou de produire manuellement une version hybride des deux.
  • Dans tous les cas, il est définitivement enregistré que la cible comprend désormais (comme étant sa nouvelle révision) les deltas sélectionnés de la source. Les fichiers source et cible peuvent en fait être considérés comme des variantes l'un de l'autre.

3.2. Historique d'intégration

L'enregistrement des deltas qui ont été fusionnés entre deux fichiers forme l'historique d'intégration pour la paire de fichiers concernée. Il dessert deux fonctions très importantes. Tout d'abord, si l'historique d'intégration indique que des deltas ont été fusionnés entre deux fichiers, cela signifie que la cible est une variante de la source. Ensuite, l'historique d'intégration peut être utilisé pour calculer quels deltas doivent encore être fusionnés. L'utilisateur qui possède cette information n'est plus obligé de sélectionner les deltas source pour chaque fusion.

L'historique d'intégration peut également servir de piste d'audit et de base à la création d'un rapport exhaustif. La fermeture transitive permet de calculer pour chaque révision de fichier les deltas incorporés à partir d'autres fichiers par le biais de fusions de première, deuxième, troisième, etc. génération.

3.3. Vue des branches

Si les fichiers d'une variante doivent être liés par leur nom, quelque chose doit exprimer cette relation. C'est précisément la tâche des vues des branches. Il s'agit d'une assignation un-à-un à laquelle un nom à été attribuée, qui s'effectue entre les noms de deux jeux de fichiers: la source et la cible de la branche prévue. Pour appliquer la vue de la branche, le nom de chaque fichier connu est assigné à une source candidate par l'intermédiaire de la vue. Les paires source/cible qui en résultent définissent les fichiers à ramifier ou fusionner.

Ce mécanisme comprend deux facettes importantes : tout d'abord, bien que chaque vue des branches permette uniquement des assignations un-à-un entre les sources et les cibles dans la vue, plusieurs vues peuvent avoir les mêmes sources et/ou cibles. Par conséquent, la même source peut être greffée sur plusieurs cibles différentes, ou peut-être moins intuitivement, la même cible peut être la variante de plusieurs sources. Ensuite, l'assignation est appliquée uniquement à la demande de l'utilisateur, plutôt que d'être appliquée dès la création ou la mise à jour de sources potentielles. Autrement dit, la vue des branches est appliquée uniquement lorsque l'utilisateur demande à créer ou à fusionner des fichiers cible.

Les vues des branches documentent simplement le fait qu'un utilisateur a prévu qu'un jeu de cibles reflète un jeu de sources. La véritable fusion s'effectue par l'intermédiaire de l'application de la vue des branches. À la demande de l'utilisateur, le nom des fichiers existants est projeté par la vue pour produire une liste des paires source/cible. Pour chaque paire, l'historique d'intégration est pris en compte et des intégrations complémentaires sont proposées à l'utilisateur. Ces propositions de modifications (création de la première révision de nouvelles variantes, création de nouvelles révisions de variantes existantes ou suppression de variantes dont les sources ont été supprimées) essaient de faire en sorte que le jeu cible reflète les deltas du jeu source. Bien entendu, l'utilisateur décide si ces modifications doivent être incorporées dans leur intégralité, modifiées ou ignorées. Il est rare que l'utilisateur souhaite conserver deux configurations parfaitement identiques.

3.4. Calcul de la base de la fusion

Nous avons précédemment mentionné que l'historique d'intégration, qui enregistre séparément les deltas d'un fichier qui ont été fusionnés, peut être utilisé pour calculer exactement quels deltas doivent encore être fusionnés. Un produit de ce calcul est utile en tant que version pour former la base d'une comparaison/fusion de fichier tridirectionnelle. Il s'agit de la révision de la source avant la première fusion.

La méthode généralement utilisée pour réconcilier les modifications apportées à un fichier consiste à rechercher un ancêtre commun et à l'utiliser comme base du processus de comparaison/fusion. Ce processus implique le calcul de la différence textuelle entre la base et chaque révision de la variante, puis la fusion de ces différences. Il a déjà été mis en œuvre dans un grand nombre d'outils, du simple programme de GCL rcsmerge aux interfaces graphiques utilisateur élaborées, qui illustrent avec beaucoup de couleurs les lignes de texte ayant été modifiées d'une version à l'autre.

La plupart des systèmes utilisent le point de ramification d'origine comme ancêtre commun. Malheureusement, alors que le texte des deux variantes s'éloigne de l'ancêtre, de plus en plus de modifications dans les variantes semblent être en conflit ou se chevaucher entre elles. Par conséquent, chaque fois que l'utilisateur fusionne les variantes, il doit revisiter chaque conflit textuel qui a été résolu dans les précédentes fusions. Une autre approche consiste à enregistrer le delta le plus élevé de la source qui a été fusionnée, comme le fait Clearcase à l'aide des liens hypertexte. Mais cela suppose que les deltas soient toujours fusionnés dans l'ordre. Il est parfois souhaitable, par exemple, de fusionner immédiatement un seul delta contenant le correctif d'un bogue, et de laisser les deltas précédents et suivants pour plus tard.

Le suivi des deltas fusionnés un à un rend toujours possible la production d'une base optimale pour la fusion, autrement dit la révision de la source avant la première fusion. Ceci minimise les différences entre la base et la tête de la source, et de ce fait, réduit la complexité de la fusion.

3.5. Intégrations "pures"

Étant donné que l'historique d'intégration assure un suivi particulier des deltas fusionnés d'une variante vers une autre, il est possible de tirer un avantage particulier en reconnaissant des intégrations pures. Il s'agit d'une intégration dans laquelle la nouvelle révision de la cible incorpore uniquement les deltas d'une source unique. L'importance tient au fait qu'un delta qui résulte d'une intégration pure n'a pas besoin d'être fusionné en retour dans la source.

Sans historique d'intégration, il n'est pas possible de savoir que le nouveau delta d'une variante cible résulte uniquement de la fusion de deltas depuis une autre variante. Toute fusion automatisée ultérieure trouverait le nouveau delta et tenterait de le fusionner en retour dans la source. Si le delta a été fusionné littéralement à l'origine, le processus de fusion réel devrait être une opération nulle et n'avoir que peu de conséquences pour l'utilisateur. Mais si le delta a nécessité une résolution de conflit ou une autre édition lors de sa fusion initiale dans la cible, l'utilisateur devra revisiter cette résolution lors de la fusion en retour.

Avec un historique d'intégration qui enregistre des intégrations pures, les fusions automatisées peuvent éviter la fusion en retour d'un delta dans sa source. En pratique, l'utilisateur doit fournir quelques informations pour signaler que l'intégration est restée pure : lors de la résolution d'un conflit, l'utilisateur a la possibilité de procéder à d'autres modifications, qui peuvent en fait nécessiter une fusion en retour. À la fin, l'utilisateur doit en fait confirmer que l'intégration est restée pure, fait qui pourra ensuite être enregistré par l'historique de l'intégration. Cet enregistrement peut être utilisé pour supprimer un essai automatisé de fusion en retour du delta dans la source.

3.6. Gestion de l'espace de noms

Si l'espace de noms hiérarchique des fichiers doit avoir une double fonction avec le nom des variantes, il est important de laisser de la place dans le nom de fichier pour le nom de la variante. Il s'agit principalement d'une utilisation distincte, mais nous estimons pour des cas simples que le positionnement du nom de la variante au début du nom de fichier simplifie la compréhension de l'arborescence. Par exemple, il est relativement facile pour des utilisateurs de comprendre que la Mainline de développement se situe sous /main/src/... tandis que la dernière version est ramifiée dans /release2.1/src/..., etc.

3.7. Vues client

Il est important que le nom des fichiers dans le référentiel de GCL ne soient pas tenus de correspondre au nom du fichier une fois entre les mains (ou dans le système de fichiers) de l'utilisateur. Si le nom doit encoder la variante, il est alors souhaitable de pouvoir supprimer cette information du nom de fichier lorsque le fichier est remis aux utilisateurs. Une vue client peut alors être utilisée : chaque espace de travail client possède une vue (un peu à l'image d'une vue des branches) qui projette le nom des fichiers dans le référentiel sur le système de fichiers local de l'utilisateur. De la sorte, une entité unique (la vue client) indique non seulement les fichiers, mais également les variantes qu'un utilisateur souhaite voir. Une telle vue peut apporter deux variantes différentes sur le client, simplement en leur donnant des noms distincts sur le client.

3.8. Variantes comme copies virtuelles

En pratique, si la ramification d'un fichier implique de le copier dans le référentiel, alors l'espace de stockage peut poser problème. Un antidote simple consiste à effectuer une copie virtuelle à l'emplacement où le fichier nouvellement ramifié utilise le contenu du fichier d'origine. Il est alors nécessaire de disposer d'un niveau d'indirection entre l'espace de noms du référentiel et le magasin d'objets sous-jacent réel. Lorsque la branche est étendue par l'ajout d'une nouvelle révision, le fichier ramifié peut acquérir sa propre entité distincte dans le magasin d'objets.

La prise en charge des variantes avec des copies virtuelles réduit l'espace requis d'une variante à un simple enregistrement de la nouvelle variante qui pointe vers le fichier d'origine. Ce n'est ni plus ni moins que le coût d'une variante traditionnelle.

Cette copie virtuelle peut également être utilisée lorsqu'une variante est explicitement synchronisée avec une autre. Si l'utilisateur souhaite plier une branche en retour dans un tronc et les rendre identiques, tous deux peuvent ici faire référence au même contenu.

4. Discussion

4.1. Comparaison avec la technologie existante

Dans cet article, Inter-File Branching a été directement comparé au modèle d'arborescence de la version présent dans les systèmes connus, tels que RCS et ClearCase. Deux autres approches de la prise en charge de la variante méritent également d'être mentionnées.

4.1.1. Modèle de Baseline

Le modèle de Baseline [2] peut être considéré comme une version considérablement simplifiée de Inter-File Branching. Une Baseline est à proprement parler une configuration qui sert de base à de futures modifications. Toutefois, dans la pratique courante, le contenu de cette configuration est copié et les fichiers ainsi copiés deviennent la véritable Baseline. De ce point de vue, il ressemble à la copie de Inter-File Branching car la nouvelle Baseline elle-même possède un nom qui la distingue de la configuration d'origine.

Par rapport à Inter-File Branching, trois restrictions sont appliquées au modèle de Baseline : premièrement, la relation des noms est fixe ; généralement, un nom est attribué aux Baselines, tandis que le nom des fichiers qu'elles contiennent est fixe d'une Baseline à l'autre. Deuxièmement, une Baseline est un jeu de fichiers prédéterminé, généralement un "projet" ou un "produit". Il n'est pas possible de créer des variantes d'un ou deux fichiers. Troisièmement, l'historique d'intégration, s'il existe, est considérablement restreint avec les Baselines. Par exemple, il n'assure pas le suivi des deltas distincts fusionnés entre deux variantes.

4.1.2. Modèle de jeu de modifications/Modèle de jeu de versions ICE

Le modèle de jeu de modifications [7] et le modèle de jeu de versions dans ICE [10] sont pratiquement l'antithèse de Inter-File Branching. Dans ces deux modèles, les variantes et les révisions ne forment pas une arborescence des noms de versions pour chaque fichier. Au contraire, chaque fichier possède un ensemble de deltas qui peut être appliqué arbitrairement pour produire une version (peut-être dépourvue de sens). Avec le modèle de jeu de modifications, la combinaison de deltas à appliquer est appelée "jeu de modifications" ; un tel jeu peut lui-même être enregistré comme faisant partie d'une configuration nommée. Avec le modèle de jeu de versions d'ICE, les deltas ont des attributs (appelés "fonctionnalités") ; les deltas sélectionnés possèdent alors la combinaison d'attributs appropriée.

Si ces deux modèles peuvent parfaitement être comparés avec le modèle d'arborescence de la version, il existe des différences marquées avec Inter-File Branching. Inter-File Branching cherche à maintenir la distinction des variantes dans l'espace de noms du référentiel, de sorte que l'utilisateur puisse les voir et les traiter comme des fichiers indépendants. Les jeux de modifications et jeux de versions, quant à eux, empilent toutes les variantes d'un fichier en une seule entité et exigent de l'utilisateur qu'il choisisse (ou crée) la version souhaitée avec chaque interaction. Pour avoir une vision d'ensemble : Inter-File Branching permet d'identifier les configurations importantes simplement par le nom des fichiers composants ; avec les arborescences de versions il y a de fortes chances que les configurations importantes ne se trouvent pas sur le tronc, les variantes doivent alors être explicitement nommées ; avec les jeux de modifications et les jeux de versions, les configurations importantes exigent sûrement une spécification explicite de la liste des jeux de modifications ou des fonctionnalités.

4.2. Évaluation empirique

Ingres Corporation a intégré une version précédente du modèle Inter-File Branching dans le cadre d'un système de GCL interne appelé Piccolo [6]. Cette version ne disposait pas des vues des branches et des détails de l'historique d'intégration présents dans le modèle actuel. Par conséquent, la création de variantes en premier lieu était peu maniable car l'utilisateur devait énumérer les fichiers particuliers à ramifier ; parfois, le système insistait (de manière répétitive) pour qu'un delta soit fusionné en retour après avoir été fusionné dans un autre fichier.

Néanmoins, Inter-File Branching s'est avéré une base solide pour la mise en œuvre d'un développement et de versions parallèles. Plusieurs centaines de développeurs et d'ingénieurs répartis sur trois continents ont utilisé la ramification de Piccolo pour la prise en charge de quelques douzaines de produits, soit un total de 12 000 fichiers. Il est arrivé qu'une douzaine de versions simultanées soient en cours.

Pour la plupart, la création des branches se faisait par la perturbation du premier composant du nom de chaque fichier stocké dans le référentiel. La Mainline de transmission était la ligne de développement qui était appelée "main". De là partaient des douzaines de branches pour les développeurs ou les groupes, chacune étant nommée d'après le développeur ou le projet. De même, des branches partaient de la Mainline pour chaque version importante, nommées d'après la version. Ces versions importantes devenaient des sous-lignes directrices, d'où poussaient des branches de correctif.

L'un des avantages inattendus de Inter-File Branching fut qu'étant donné que les branches étaient exprimées en relation avec le nom de deux fichiers arbitraires, les développeurs pouvaient créer des branches qui avaient une structure d'arborescence différente de la Mainline. Ce qui leur a permis de créer et de maintenir leur produit dans un environnement personnalisé selon leurs besoins. Par exemple, un groupe pouvait être responsable des répertoires "très à l'écart" dans l'espace de noms de la Mainline. Pour plus de confort, ils pouvaient rassembler ces répertoires dans la branche de leur groupe.

Le modèle Inter-File Branching actuel, tel que nous venons de le décrire, est mis en œuvre dans un système commercial, Perforce. Perforce est une tentative de création délibérée à partir de la sémantique de Inter-File Branching tout en apportant une solution aux déficiences détectées dans la mise en œuvre de Piccolo. Bien que Perforce soit un produit récent, une expérience anticipée démontre que le modèle est flexible, exploitable et relativement complet. Nous espérons que l'enregistrement de l'historique d'intégration se révélera une source d'informations précieuses dans un grand produit logiciel évolué, mais nous n'avons pas encore connaissance d'un tel produit.

5. Conclusion

La popularité d'une gestion traditionnelle des variantes vient démentir les rumeurs d'un modèle fondamentalement non naturel. Bien que les utilisateurs confirmés des systèmes de GCL actuels comprennent l'utilisation d'une variante et d'un espace de noms combinés, la faiblesse des bases de cette approche conduit éventuellement à un ensemble de lacunes dans sa capacité totale. Inter-File Branching, d'autre part, commence par un modèle naturel, à savoir la copie de fichiers logiciels et l'attribution d'un nouveau nom, et termine par le recueil des techniques qui rendent le modèle utilisable. Si on lui en donne la possibilité, Inter-File Branching pourrait rivaliser avec la fonctionnalité de gestion traditionnelle des variantes.

6. Bibliographie

[1] Atria Corporation, ClearCase Concepts Manual. Natick Massachusetts, 1994

[2] Bersoff, Henderson, Siegel, Software Configuration Management. Prentice-Hall, 1980.

[3] Susan Dart, The Past, Present, and Future of Configuration Management. Technical Report CMU/SEI-92-TR-8, Software Engineering Institute, Carnegie Mellon University, 1992.

[4] Stephen MacKay, The State of the Art in Concurrent, Distributed Configuration Management. Proceedings of the 5th International Workshop on Software Configuration Management, Seattle, WA, 1995.

[5] Rochkind, The Source Code Control System. IEEE Transactions on Software Engineering, Volume SE-1, décembre 1975.

[6] Roger Rohrbach and Christopher Seiwald, Galileo: A Software Maintenance Environment. Proceedings of the International Workshop on Software Version and Configuration Control, Grassau, 1988.

[7] Software Maintenance and Development Systems (SMDS). Aide-de-Camp Users Manual, Concord Mass, 1993.

[8] Walter Tichy, RCS -- a system for version control. Software -- Practice and Experience, juillet 1985.

[9] Walter Tichy, Tools for Software Configuration Management. Proceedings of the International Workshop on Software Version and Configuration Control, Grassau, 1988.

[10] Andreas Zeller, Smooth Operations with Square Operators -- The Version Set Model in ICE. Informatik-Bericht N° 95-08, Technical University of Braunschweig, Allemagne, 1995.