Disposition du référentiel (ou raccordement) pour créer des branches pour les bibliothèques partagées (et préserver votre santé mentale)

StackOverflow https://stackoverflow.com/questions/1400199

Question

Nous utilisons Subversion (la question pourrait s’appliquer à de nombreux systèmes de contrôle de versions, mais la subversion est celle qui m’intéresse vraiment.)

Notre structure de référentiel ressemble à ce qui suit:

(mise en page A)

Web
  branches
  tags
  trunk
Libraries
  Foo
    branches
    tags
    trunk
  Bar
    branches
    tags
    trunk
WindowsClient
  branches
  tags
  trunk
DB
  branches
  tags
  trunk

Le problème est que l'unité de version ne correspond pas à l'unité de développement. Je dois effectuer plusieurs extractions pour obtenir un artefact à construire. Lorsque je branche, je dois créer une branche pour plusieurs composants (et archiver plusieurs endroits.)

Cela implique que nous pourrions plutôt passer à une structure comme celle-ci:

(mise en page B)

Web
  branches
  tags
  trunk
    main
    libs
      Foo
      Bar
    DB
WindowsClient
  branches
  tags
  trunk
    main
    libs
      Foo
      Baz
    DB

Mais nous avons des copies de toutes les bibliothèques partagées. Nous pourrions mapper les bibliothèques partagées en utilisant svn: externals, mais ce n'est qu'une illusion: elles ne seront pas branchées lorsque le projet contenant le sera.

Une dernière option est la suivante:

(mise en page C)

branches
tags
trunk
  Web
  Libraries
    Foo
    Bar
  WindowsClient
  DB

Cela garantit que les bibliothèques sont branchées avec le projet qui les contient, mais au prix coûtant que l'unité de branchement est le monde entier. (Cela implique également que l’unité de paiement est le monde entier, ce qui est gênant également.)

Ce que je veux, c'est une structure de référentiel (Présentation D) qui me permet de:

  • Branchement simultané d'un projet et de ses bibliothèques dépendantes
  • Partage de bibliothèques entre projets

Ce serait bien si je pouvais consulter le projet et ses bibliothèques en une seule fois, mais ce n’est pas aussi important que ce qui précède.

La question est donc:

Existe-t-il une mise en page D, qu'est-ce que c'est et comment l'utiliser?

Modifier: Puisqu'il semble qu'aucune disposition de base ne me donne ces propriétés, je serais très intéressé par une sorte de fonction de raccordement pour y parvenir. Ce serait particulièrement bien si cela fonctionnait avec le client TortoiseSVN (Windows GUI), car c'est ce que nous utilisons.

Était-ce utile?

La solution

Choisissez l’option C, puis effectuez votre commande de la manière suivante:

svn co -N ...../branches/mybranch workingcopy
cd workingcopy
svn update Web Libraries

Désormais, lorsque vous effectuerez des opérations svn (y compris un " svn update " brut), cela ne concernera que les Web et les bibliothèques répertoires.

Lisez également les répertoires clairsemés .

Autres conseils

Il n'y a pas de bonne réponse à la question "Comment structurer mon référentiel pour ce flux de travail?" parce que le logiciel ne supporte pas vraiment ça. Je suggérerais d'utiliser votre modèle B, de créer une branche pour le code de bibliothèque et de changer le svn: external approprié vers cette branche, ou tout de suite si vos branches doivent faire référence à une version hors ligne. de la bibliothèque.

J'allais suggérer que Git gère cela mieux, mais pas beaucoup. Étant donné que ses sous-modules font référence à des référentiels distincts légèrement différents des externals, et que chaque copie du référentiel est une "branche", cela pourrait constituer une légère amélioration.

  

Nous pourrions mapper les bibliothèques partagées en utilisant   svn: externals, mais c'est juste un   illusion - Ils ne seront pas ramifiés   lorsque le projet contenant est.

En fait, ils seront branchés s'ils se trouvent dans le même référentiel et que vous avez utilisé la syntaxe externe relative, par exemple. ^ \ mylib \ trunk . Ces références externes sont transformées en dossiers normaux (copiés). Vous devez explicitement passer - ignore-externals à svn copy pour supprimer ce problème, sinon vous obtiendrez des copies similaires à celles du modèle B. ( modifier : j'étais à peu près sûr que cela fonctionnait ainsi, mais je n'arrive pas à reproduire ce comportement. J'ai dû me tromper, désolé!)

Le fait que les externes ne se connectent pas toujours automatiquement ne doit pas être un problème. J'utiliserais la mise en page B construite avec svn: externals (pas des copies), branchez le projet (avec - ignore-externals ), puis après la création d'une branche, adaptez le svn: externals pour qu'il pointe vers le corrigez les branches de la bibliothèque.

Vous pouvez configurer les externes pour qu'ils pointent vers une révision spécifique (bon pour un contrôle strict; vous décidez quand passer à une nouvelle révision de la liste) ou tout simplement le suivi de HEAD (bon pour l'intégration continue, en supposant que vous disposiez d'une construire le serveur mis en place).

Comme nous l'avons résolu pour les bibliothèques externes partagées utilisées par plusieurs projets, la bibliothèque partagée se trouve dans son propre référentiel avec ses propres troncs / branches / balises.

Nous disposons ensuite d'un serveur de build, qui publie et publie des builds d'intégration, des jalons et des éditions, et l'artefact binaire est copié dans un emplacement partagé et stocké dans des répertoires spécifiques à la version (ceux-ci sont sauvegardés).

Une partie du script de construction d'un projet dépendant (normalement exécutée à la demande en tant qu'initialisation / mise à jour plutôt que dans le cadre d'une construction standard), puis recherche de nouvelles versions et récupère le binaire. Cela présente l'avantage d'une gestion cohérente des versions de l'artefact partagé entre les projets dépendants et réduit le temps de construction, car tous les projets dépendants peuvent partager la même version.

Pour nous aider dans la gestion des versions, nous utilisons actuellement Apache Ivy , qui prend en charge des dépendances transitoires (par exemple, récupérer les dépendances d’une dépendance) et les contraintes de version (par exemple, ce projet ne doit utiliser que Foo version 1.2. *).

Je suggérerais que c'est votre approche de ces bibliothèques qui est à l'origine de vos problèmes. Vous pouvez changer cela si vous commencez à considérer les bibliothèques comme des projets distincts. Considérez-les comme ayant leurs propres raisons d’être, leur propre conception et leurs propres cycles de publication, tout comme les bibliothèques tierces que vous pouvez utiliser pour les tests unitaires, les lecteurs xml, l’accès à la base de données, etc.

Bien sûr, vous rencontrerez régulièrement des moments où une fonctionnalité d’un projet nécessite une nouvelle fonctionnalité dans une bibliothèque. L'implémentation de la fonctionnalité de bibliothèque et l'utilisation de la fonction de bibliothèque sont deux tâches indépendantes. Il peut s'agir d'une tâche commerciale mais de deux tâches de développement. Il n'est pas nécessaire de lier étroitement les deux activités simplement parce que c'est ainsi que le travail a été créé. Extrayez la bibliothèque, modifiez-la, relâchez-la, puis extrayez votre projet et utilisez la nouvelle version de la bibliothèque dans votre projet.

Je suis convaincu que la séparation des bibliothèques dans leurs propres troncs est une bonne chose. Je ne peux pas le supporter lorsque je vois plusieurs projets pouvant être divulgués indépendamment sous un seul tronc. Il sent de mauvaise conception et a été bloqué dans un coin par le développement cruel. Mais pour les séparer, vous devez être en mesure de publier chaque projet indépendamment - pour moi, c’est ce que signifie avoir plusieurs projets signifie . Mais ce n’est pas difficile à faire:

Tout d'abord, un projet utilise des références externes pour référencer une version publiée spécifique d'une bibliothèque. C'est la seule façon dont un projet fait référence à une bibliothèque. Cela signifie que les développeurs peuvent créer une nouvelle version de la bibliothèque sans interrompre aucun des projets l'utilisant, car tous les projets référenceront la version précédente. Les projets contrôlent le moment où ils souhaitent importer de nouvelles versions de bibliothèques. Les développeurs peuvent choisir entre le moment où ils souhaitent mettre à l'essai leur code avec la nouvelle version et le moment opportun pour résoudre les problèmes de construction de la nouvelle bibliothèque. introduit.

Lorsque vous modifiez explicitement les versions d'une bibliothèque comme celle-ci, vous obtenez également dans votre projet une entrée indiquant "J'utilise maintenant cette version de la bibliothèque X", ce qui vous donne une bonne sens de l'histoire dans votre projet quant à quand les choses fonctionnaient et exactement quand les choses ont changé.

Bien sûr, tout cela est beau en théorie, mais dans la pratique, les développeurs devront parfois faire référence à des versions instables et inachevées d’une bibliothèque. C'est bien, un développeur peut toujours changer sa copie de travail pour pointer sur le coffre de la bibliothèque plutôt que sur une balise ou sur une branche de développement, et utiliser le code à partir de là (même y travailler s'il le faut, brrr). Un commutateur est juste une édition locale, donc n'aura aucun effet sur le code engagé. Si le développement du projet est sur une branche instable, vous pouvez décider de rendre le commutateur plus permanent en modifiant la référence externe jusqu'à ce que la branche soit prête à être réintégrée, mais cela ne serait normalement pas fait sans raison explicite.

Enfin, la création de branches et de balises dans votre projet devient un simple cas de création d’une branche ou d’une balise de votre projet principal - c’est tout. Il n'y a pas besoin de s'inquiéter des bibliothèques de branchement - elles prennent soin d'elles-mêmes. Le processus de modification d'une bibliothèque ne change pas si le projet est dans un coffre, une branche de développement ou une version de maintenance. Et vos bibliothèques peuvent avoir elles-mêmes des branches de développement totalement indépendantes des projets principaux, ainsi que de multiples versions prises en charge, etc., jusqu'au niveau de complexité que vous souhaitez et que vous pouvez prendre en charge.

En utilisant des références externes sur votre ligne de réseau ou votre branche de développement, vous pouvez effectuer une extraction unique pour créer votre espace de travail dans la structure dont vous avez besoin. Étant donné que toutes les bibliothèques se trouvent sous la racine principale, vous pouvez effectuer plusieurs extractions de plusieurs versions sans créer de conflit.

J'ai trouvé que ce système fonctionnait plutôt bien et qu'après avoir déplacé des tâches dans un endroit qui ne fonctionne pas de cette façon, je me sens désolé pour la méthode de travail précédente. Il y a des problèmes, principalement liés aux bibliothèques en fonction des bibliothèques et de l'opportunité d'avoir des externaux récursifs. Mon point de vue est de devenir récursif sauf si cela cause un problème (ou une douleur excessive), puis de passer à un modèle «dégénéré» dans lequel le projet doit connaître certaines dépendances «profondes», même s'il ne les utilise pas directement. En outre, décidez où vous allez mettre vos définitions d'externals et vous y tenez, rien n'est plus ennuyeux que de rechercher ces propriétés svn: externals sur des dossiers aléatoires de différents projets. Les mettre à la racine du tronc va bien.

Il s’agit d’un problème difficile qui n’a pas de solution satisfaisante; la solution idéale consiste à utiliser un “ lignes de produits logiciels ”(par exemple, pure :: variants ). Cependant, la plupart d’entre nous n’utilisons pas cette correspondance pour un système de contrôle de code source.

Par conséquent, je choisirais LayoutA - avec chaque bibliothèque versionnée séparément. Cependant, j'aurais tendance à placer " trunk " sous " branches " car il s'agit d'une branche et j'aime avoir toutes les branches à la même distance du haut.

La prochaine étape dépend plutôt de votre système de génération, je suppose ici Visual Studio.

  • À la racine de chaque branche de produit
  • Créez un fichier bat qui définit une variable d'environnement contenant le nom de la branche de chaque bibliothèque que vous souhaitez utiliser
  • Editez les fichiers de projet Visual Studio pour référencer les bibliothèques à l'aide de ces variables d'environnement
  • Exécutez le fichier de commandes à partir de l'invite de commande Visual Studio avant de démarrer Visual Studio

Vous pouvez également envisager d’écrire un fichier MSBuild personnalisé plutôt que d’utiliser un fichier de commandes. Ou encore, rédigez un outil qui édite tous les fichiers du projet lorsque vous changez la version d'une bibliothèque.

Si vous ne possédez qu'une ou deux bibliothèques partagées et qu'elles ne changent que pour un produit à la fois, par exemple. d'ajouter de nouvelles méthodes pour le projet sur lequel on travaille actuellement. J'envisagerais de créer une branche différente de la bibliothèque pour chaque projet et d'utiliser SVN 1.5 Fusion Tacking pour suivre l'évolution de la situation. (Lorsque les modifications sont stables, fusionnez-les avec le camion, puis fusionz-les à chaque branche de projet, le cas échéant)

(Si vous avez des centaines de bibliothèques, vous devez suivre la version de chaque bibliothèque qui en a besoin. Cela commence à être très complexe!)

Je n’ai pas aimé svn: external, ce qui se passe n’est pas clair à partir du système de fichiers de votre PC local. Cependant, svn: external est une solution viable.

Ayant vécu un problème similaire, je connais votre douleur. La gestion des dépendances dans un référentiel avec des composants hiérarchiques est un problème difficile.

Notre projet comportait plusieurs produits (quels que soient les produits que vous livrez aux clients) composés de divers composants (dont beaucoup sont partagés). Chaque composant possédait sa propre trilogie tags / branches / trunk , un peu comme votre Layout A (qui est après tout le mode recommandé).

Nous avons utilisé svn: externals pour permettre à chaque produit de spécifier des composants dépendants (et des sous-composants, etc.). Au début, cela a fonctionné relativement bien. Mais nous avons finalement rencontré des problèmes, tels que ce qui se passe lorsque vous branchez, si un produit doit épingler une dépendance à une révision donnée, comment propager des balises via des externes pour la gestion de la configuration (afin de pouvoir réellement reconstruire le même arbre!) , etc. Donc svn: externals résout certains problèmes mais en présente d’autres.

J'ai fini par écrire des scripts pour gérer cela, mais c'était quand même un peu compliqué. Heureusement, vous pouvez utiliser les liaisons Python-Subversion pour écrire des applications Python afin de manipuler des propriétés. Vous pouvez ainsi faire en sorte que les balises soient propagées via des composants dépendants, etc.

.

Il existe un projet conçu pour résoudre ce problème même des modules dépendants, appelé Piston . Cela ressemble à un très bel outil générique pour exactement ce genre de problème. Je ne l'ai pas déployé en production, mais à l'époque, il semblait que cela ferait presque tout ce dont nous avons besoin. Et cela semble certainement être une solution plus flexible que celle proposée par externals (qui reste un processus très manuel).

Résultat inférieur: vous pouvez vous en tenir à la disposition A et utiliser Piston pour gérer les dépendances afin que toutes les versions appropriées de vos bibliothèques soient assemblées dans votre répertoire de travail.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top