Comment organisez-vous votre référentiel de contrôle de version?

108

Tout d'abord, je sais à ce sujet: comment organiseriez-vous un référentiel Subversion pour des projets logiciels internes? Ensuite, la vraie question: mon équipe est en train de restructurer notre référentiel et je cherche des astuces pour l'organiser. (SVN dans ce cas). Voici ce que nous avons trouvé. Nous avons un référentiel, plusieurs projets et plusieurs svn: références croisées externes

\commonTools /*tools used in all projects. Referenced in each project with svn:externals*/
   \NUnit.v2.4.8
   \NCover.v.1.5.8
   \<other similar tools>
\commonFiles /*settings strong name keys etc.*/
   \ReSharper.settings
   \VisualStudio.settings
\trash /*each member of the team has trash for samples, experiments etc*/
   \user1
   \user2
\projects
   \Solution1 /*Single actual project (Visual Studio Solution)*/
      \trunk
         \src
             \Project1 /*Each sub-project resulting in single .dll or .exe*/
             \Project2
         \lib
         \tools
         \tests
         \Solution1.sln
      \tags
      \branches
   \Solution2
      \trunk
         \src
             \Project3 /*Each sub-project resulting in single .dll or .exe*/
             \Project1 /*Project1 from Solution1 references with svn:externals*/
         \lib
         \tools
         \tests
         \Solution2.sln
      \tags
      \branches

Pour effacer le vocabulaire: Solution signifie produit unique, Projet est un projet Visual Studio (qui se traduit par un seul .dll ou un .exe unique)

C'est ainsi que nous prévoyons de disposer le référentiel. Le principal problème est que nous avons plusieurs solutions, mais que nous voulons partager les projets entre les solutions. Nous avons pensé qu'il était vraiment inutile de déplacer ces projets partagés vers leurs propres solutions, et à la place, nous avons décidé d'utiliser svn: externals pour partager les projets entre les solutions. Nous souhaitons également conserver un ensemble commun d'outils et de bibliothèques tierces au même endroit dans le référentiel, et les référencer dans chaque solution avec svn: externals.

Que pensez-vous de cette mise en page? Surtout à propos de l'utilisation de svn: externals. Ce n'est pas une solution idéale, mais compte tenu de tous les avantages et inconvénients, c'est la meilleure à laquelle nous puissions penser. Comment feriez-vous cela?

Krzysztof Kozmic
la source
Êtes-vous sûr que vous voulez dire "thrash"? Ou plutôt "poubelle"?
ssc

Réponses:

92

Si vous suivez mes recommandations ci-dessous (je l'ai depuis des années), vous pourrez:

- placez chaque projet n'importe où dans le contrôle de code source, tant que vous conservez la structure du répertoire racine du projet vers le bas

- construire chaque projet n'importe où sur n'importe quelle machine, avec un minimum de risque et une préparation minimale

- construire chaque projet complètement autonome, tant que vous avez accès à ses dépendances binaires (répertoires "bibliothèque" et "sortie" locaux)

- construire et travailler avec n'importe quelle combinaison de projets, car ils sont indépendants

- construire et travailler avec plusieurs copies / versions d'un même projet, car elles sont indépendantes

- évitez d'encombrer votre référentiel de contrôle de source avec des fichiers ou des bibliothèques générés

Je recommande (voici le boeuf):

  1. Définissez chaque projet pour produire un seul livrable principal, tel qu'un .DLL, .EXE ou .JAR (par défaut avec Visual Studio).

  2. Structurez chaque projet comme une arborescence de répertoires avec une seule racine.

  3. Créez un script de construction automatisé pour chaque projet dans son répertoire racine qui le construira à partir de zéro, sans aucune dépendance sur un IDE (mais ne l'empêchez pas d'être construit dans l'EDI, si possible).

  4. Envisagez des projets nAnt pour .NET sous Windows, ou quelque chose de similaire en fonction de votre système d'exploitation, de votre plate-forme cible, etc.

  5. Faites en sorte que chaque script de construction de projet fasse référence à ses dépendances externes (tierces) à partir d'un seul répertoire de "bibliothèque" partagé local, avec chaque binaire COMPLÈTEMENT identifié par la version: %DirLibraryRoot%\ComponentA-1.2.3.4.dll, %DirLibraryRoot%\ComponentB-5.6.7.8.dll.

  6. Faites en sorte que chaque script de génération de projet publie le livrable principal dans un seul répertoire de "sortie" partagé local: %DirOutputRoot%\ProjectA-9.10.11.12.dll, %DirOutputRoot%\ProjectB-13.14.15.16.exe.

  7. Faites en sorte que chaque script de construction de projet fasse référence à ses dépendances via des chemins absolus configurables et entièrement versionnés (voir ci-dessus) dans les répertoires "bibliothèque" et "sortie", ET NON O AILLEURS.

  8. Ne laissez JAMAIS un projet référencer directement un autre projet ou l'un de ses contenus - n'autorisez que les références aux principaux livrables dans le répertoire "output" (voir ci-dessus).

  9. Faites de chaque script de compilation du projet référence à ses outils de construction requis par un chemin absolu configurable et entièrement versionné: %DirToolRoot%\ToolA\1.2.3.4, %DirToolRoot%\ToolB\5.6.7.8.

  10. Faire tous les projets de construction de contenu source de référence de script par un chemin absolu par rapport au répertoire racine du projet: ${project.base.dir}/src, ${project.base.dir}/tst(syntaxe varie selon outil de build).

  11. TOUJOURS exiger qu'un script de construction de projet fasse référence à CHAQUE fichier ou répertoire via un chemin absolu et configurable (enraciné dans un répertoire spécifié par une variable configurable): ${project.base.dir}/some/dirsou ${env.Variable}/other/dir.

  12. NE JAMAIS autoriser un script de génération de projet à référencer QUELQUE CHOSE avec un chemin relatif tel que .\some\dirs\hereou ..\some\more\dirs, TOUJOURS utiliser des chemins absolus.

  13. NE JAMAIS autoriser un script de construction de projet à référencer QUELQUE CHOSE en utilisant un chemin absolu qui n'a pas de répertoire racine configurable, comme C:\some\dirs\hereou \\server\share\more\stuff\there.

  14. Pour chaque répertoire racine configurable référencé par un script de génération de projet, définissez une variable d'environnement qui sera utilisée pour ces références.

  15. Essayez de réduire le nombre de variables d'environnement que vous devez créer pour configurer chaque machine.

  16. Sur chaque machine, créez un script shell qui définit les variables d'environnement nécessaires, qui sont spécifiques à CETTE machine (et éventuellement spécifiques à cet utilisateur, le cas échéant).

  17. Ne placez PAS le script shell de configuration spécifique à la machine dans le contrôle de code source; à la place, pour chaque projet, validez une copie du script dans le répertoire racine du projet en tant que modèle.

  18. EXIGEZ que chaque script de génération de projet vérifie chacune de ses variables d'environnement et abandonne avec un message significatif si elles ne sont pas définies.

  19. EXIGEZ que chaque script de construction de projet vérifie chacun de ses exécutables d'outil de construction dépendants, les fichiers de bibliothèque externes et les fichiers livrables de projet dépendants, et abandonne avec un message significatif si ces fichiers n'existent pas.

  20. RÉSISTEZ à la tentation de valider TOUS les fichiers générés dans le contrôle de code source - pas de livrables de projet, pas de source générée, pas de documents générés, etc.

  21. Si vous utilisez un IDE, générez les fichiers de contrôle de projet que vous pouvez et ne les validez pas dans le contrôle de code source (cela inclut les fichiers de projet Visual Studio).

  22. Établissez un serveur avec une copie officielle de toutes les bibliothèques et outils externes, à copier / installer sur les postes de travail des développeurs et à construire des machines. Sauvegardez-le, avec votre référentiel de contrôle de source.

  23. Établissez un serveur d'intégration continue (build machine) sans aucun outil de développement.

  24. Envisagez un outil pour gérer vos bibliothèques externes et vos livrables, comme Ivy (utilisé avec Ant).

  25. N'utilisez PAS Maven - cela vous rendra d'abord heureux et finira par vous faire pleurer.

Notez que rien de tout cela n'est spécifique à Subversion, et que la plupart d'entre eux sont génériques pour les projets ciblés sur n'importe quel système d'exploitation, matériel, plate-forme, langage, etc. J'ai utilisé un peu de syntaxe spécifique au système d'exploitation et à l'outil, mais uniquement à titre d'illustration. -J'espère que vous traduirez vers votre système d'exploitation ou l'outil de votre choix.

Note supplémentaire concernant les solutions Visual Studio: ne les mettez pas dans le contrôle de code source! Avec cette approche, vous n'en avez pas du tout besoin ou vous pouvez les générer (tout comme les fichiers de projet Visual Studio). Cependant, je trouve préférable de laisser les fichiers de solution aux développeurs individuels pour qu'ils les créent / les utilisent comme ils l'entendent (mais pas archivés dans le contrôle de code source). Je garde un Rob.slnfichier sur mon poste de travail à partir duquel je référence mon (mes) projet (s) en cours. Étant donné que mes projets sont tous autonomes, je peux ajouter / supprimer des projets à volonté (cela signifie qu'aucune référence de dépendance basée sur un projet).

Veuillez ne pas utiliser d'externes Subversion (ou similaires dans d'autres outils), ils sont un anti-pattern et, par conséquent, inutiles.

Lorsque vous implémentez l'intégration continue, ou même si vous souhaitez simplement automatiser le processus de publication, créez un script pour celle-ci. Créez un script shell unique qui: prend les paramètres du nom du projet (comme indiqué dans le référentiel) et du nom de la balise, crée un répertoire temporaire dans un répertoire racine configurable, extrait la source pour le nom de projet et le nom de balise donnés (en construisant le URL appropriée dans le cas de Subversion) vers ce répertoire temporaire, effectue une compilation propre qui exécute les tests et conditionne le livrable. Ce script shell doit fonctionner sur n'importe quel projet et doit être archivé dans le contrôle de code source dans le cadre de votre projet "outils de construction". Votre serveur d'intégration continue peut utiliser ce script comme base pour la création de projets, ou il peut même le fournir (mais vous pouvez toujours vouloir le vôtre).

@VonC: Vous ne voulez PAS travailler à tout moment avec "ant.jar" plutôt qu'avec "ant-abcdjar" après avoir été brûlé lorsque votre script de construction est interrompu parce que vous l'avez exécuté sans le savoir avec une version incompatible de Ant. Ceci est particulièrement courant entre Ant 1.6.5 et 1.7.0. En généralisant, vous voulez TOUJOURS savoir quelle version spécifique de CHAQUE composant est utilisée, y compris votre plate-forme (Java ABCD) et votre outil de construction (Ant EFGH). Sinon, vous rencontrerez éventuellement un bogue et votre premier gros problème sera de savoir quelles versions de vos différents composants sont impliquées. Il vaut simplement mieux résoudre ce problème dès le départ.

Rob Williams
la source
6
Autant de points à critiquer ... il suffit de dire que ce n'est pas une recette universelle! Les points 5 et 6 en particulier sont tellement faux lorsque le projet est gros et que le nombre de tiers est important: vous voulez travailler à tout moment avec 'ant.jar', pas 'ant1.5.4.jar', ou product myProduct .exe, pas 1.3.exe
VonC
5
Pourtant, +1 pour de nombreux autres points que vous faites valoir qui sont valables et qui témoignent de votre vaste expérience sur le sujet.
VonC
3
J'aimerais entendre et interagir avec vos critiques - chaque point est basé sur la résolution de mauvaises expériences avec de grands projets. Par exemple, résoudre le problème de savoir quelles versions sont représentées par Xxx.jar et Yyy.exe, en particulier lorsqu'il y a littéralement une douzaine de copies référencées.
Rob Williams
2
@Rob - Pouvez-vous élaborer sur votre thème «anti-modèle externe»? Je l'ai soulevé comme une question ici: stackoverflow.com/questions/338824/…
Ken
3
@Makis: Vous auriez raison, IF # 12 n'était pas équilibré par # 13. Chaque référence à un fichier ou un répertoire dans chaque projet doit être faite via un chemin absolu qui commence par une variable de répertoire racine configurable, par exemple $ {basedir} /sub/dir/file.txt dans Ant.
Rob Williams
3

Nous avons configuré le nôtre pour qu'il corresponde presque exactement à ce que vous avez publié. Nous utilisons la forme générale:

\Project1
   \Development (for active dev - what you've called "Trunk", containing everything about a project)
   \Branches (For older, still-evolving supported branches of the code)
       \Version1
       \Version1.1
       \Version2
   \Documentation (For any accompanying documents that aren't version-specific

Bien que je suppose que ce n'est pas aussi complet que votre exemple, cela a bien fonctionné pour nous et nous permet de garder les choses séparées. J'aime l'idée que chaque utilisateur ait également un dossier "Thrash" - actuellement, ces types de projets ne se retrouvent pas dans le contrôle de source, et j'ai toujours pensé qu'ils devraient.

SqlRyan
la source
3
Je suis surpris que vous ayez un répertoire séparé pour les documents qui ne changent pas entre les versions ... Je n'ai jamais eu le plaisir de travailler sur un tel produit! :)
ARKBAN
1

Pourquoi tout avoir dans un seul référentiel? Pourquoi ne pas avoir simplement un référentiel distinct pour chaque projet (je veux dire «Solution»)?

Eh bien, au moins, je suis habitué à l'approche d'un projet par référentiel. Votre structure de référentiel me semble trop compliquée.

Et combien de projets prévoyez-vous de mettre dans ce grand référentiel? 2? 3? dix? 100?

Et que faites-vous lorsque vous annulez le développement d'un projet? Supprimez-le simplement de l'arborescence du référentiel pour qu'il devienne difficile à trouver à l'avenir. Ou le laisser traîner pour toujours? Ou lorsque vous souhaitez déplacer un projet vers un autre serveur?

Et qu'en est-il du désordre de tous ces numéros de version? Les numéros de version d'un projet vont comme 2, 10, 11, tandis que l'autre va comme 1, 3, 4, 5, 6, 7, 8, 9, 12 ...

Peut-être que je suis stupide, mais j'aime un projet par référentiel.

René Saarsoo
la source
1. Un référentiel est une politique d'entreprise, cela ne peut pas changer. 2. Nous aurons une douzaine de solutions. 3. Par numéros de version, vous entendez les révisions? Ce n'est pas un problème pour nous.
Krzysztof Kozmic
Une bonne structure de projet doit ignorer le reste de la structure du référentiel, en particulier en ce qui concerne un ou plusieurs référentiels. Veuillez consulter ma réponse détaillée.
Rob Williams
1
Veuillez noter qu'avoir plusieurs référentiels dans de nombreux (la plupart?) Outils de contrôle de source peut être TRÈS coûteux, comme lorsque vous implémentez la sécurité.
Rob Williams
0

Je pense que le principal inconvénient de la structure proposée est que les projets partagés ne seront versionnés qu'avec la première solution à laquelle ils ont été ajoutés (à moins que svn: externals soit plus sophistiqué que ce que j'imagine). Par exemple, lorsque vous créez une branche pour la première version de Solution2, Project1 ne sera pas ramifié car il réside dans Solution1. Si vous avez besoin de construire à partir de cette branche ultérieurement (version QFE), il utilisera la dernière version de Project1 plutôt que la version de Project1 au moment de la branche.

Pour cette raison, il peut être avantageux de placer les projets partagés dans une ou plusieurs solutions partagées (et donc dans les répertoires de premier niveau de votre structure), puis de les regrouper à chaque version de n'importe quelle solution.

C. Dragon 76
la source
Vous avez raison dans une certaine mesure. Mais nous pouvons mettre à jour la référence si nous le souhaitons. Et intégrer des projets partagés dans leur propre solution n'a pas non plus beaucoup de sens. Bien que j'aimerais trouver une meilleure solution que svn: des externes partout.
Krzysztof Kozmic
Qu'entendez-vous par «mettre à jour la référence si nous le voulons»? Je ne vois pas comment vous seriez capable de créer une branche Project1 (ce qui semble souhaitable chaque fois que vous branchez Solution2) sans branchez Solution1.
C. Dragon 76
Veuillez consulter ma réponse détaillée, en particulier pour NE PAS mettre les solutions Visual Studio dans le contrôle de code source.
Rob Williams
0

Pour ajouter au problème du chemin relatif:

Je ne suis pas sûr que ce soit un problème: il
suffit de vérifier Solution1 / trunk sous le répertoire nommé "Solution1", idem pour Solution2: le but des "répertoires" représentant réellement les branches est de ne pas être visibles une fois importés dans un espace de travail. Par conséquent, des chemins relatifs sont possibles entre «Solution1» (en fait «Solution1 / trunk») et «Solution2» (Solution2 / trunk).

VonC
la source
Cela se briserait très facilement, veuillez consulter ma réponse détaillée.
Rob Williams
0

RE: le chemin relatif et le problème du fichier partagé -

Il semble que ce soit spécifique à svn, mais ce n'est pas un problème. Une autre personne a déjà mentionné des référentiels séparés et c'est probablement la meilleure solution à laquelle je puisse penser dans le cas où vous avez différents projets faisant référence à d'autres projets arbitraires. Dans le cas où vous n'avez pas de fichiers partagés, la solution OP (ainsi que beaucoup d'autres) fonctionnera correctement.

Nous travaillons toujours là-dessus et j'ai 3 efforts différents (clients différents) que je dois résoudre maintenant depuis que j'ai pris en charge la configuration d'un contrôle de version inexistant ou médiocre.

Tim
la source
Faire référence à d'autres projets crée un cauchemar de maintenance car les dépendances croissent de façon exponentielle et les références sont TRÈS fragiles. Veuillez consulter ma réponse détaillée.
Rob Williams
0

J'ai une disposition similaire, mais mon tronc, mes branches, mes balises tout en haut. Donc: / trunk / main, / trunk / utils, / branches / release /, etc.

Cela s'est avéré très pratique lorsque nous voulions essayer d'autres systèmes de contrôle de version, car de nombreux outils de traduction fonctionnaient mieux avec la mise en page SVN de base du manuel.

Peter Mortensen
la source