web-dev-qa-db-fra.com

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

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 restructure notre référentiel et je cherche des astuces pour organiser il. (SVN dans ce cas). Voici ce que nous avons trouvé. Nous avons un référentiel, plusieurs projets et plusieurs références croisées svn: externals

\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, Project est un projet Visual Studio (qui se traduit par un seul .dll ou un seul .exe)

C'est ainsi que nous prévoyons de disposer le référentiel. Le problème principal est que nous avons plusieurs solutions, mais nous voulons partager des projets entre les solutions. Nous pensions qu'il était 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 des projets entre des solutions. Nous voulons également conserver un ensemble commun d'outils et de bibliothèques tierces en un seul 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 le meilleur auquel nous puissions penser. Comment le feriez-vous?

108
Krzysztof Kozmic

Si vous suivez mes recommandations ci-dessous (je les 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

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

- construire chaque projet de manière totalement 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 ils sont indépendants

- évitez d'encombrer votre référentiel de contrôle de code source avec les fichiers ou 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 dépendances sur un IDE (mais ne l'empêchez pas d'être construit dans l'IDE, si possible) ).

  4. Considérez les projets nAnt pour .NET sous Windows, ou quelque chose de similaire en fonction de votre système d'exploitation, de la 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, chaque binaire étant ENTIÈREMENT identifié par la version: %DirLibraryRoot%\ComponentA-1.2.3.4.dll, %DirLibraryRoot%\ComponentB-5.6.7.8.dll.

  6. Faire en sorte que chaque script de construction 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 AUCUN AUTRE.

  8. NE JAMAIS laisser un projet référencer directement un autre projet ou l'un de ses contenus - autoriser uniquement les références aux livrables principaux dans le répertoire "output" (voir ci-dessus).

  9. Faites que chaque script de construction de 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. Rendre chaque contenu source de référence de script de génération de projet par un chemin absolu par rapport au répertoire racine du projet: ${project.base.dir}/src, ${project.base.dir}/tst (la syntaxe varie selon l'outil de construction).

  11. TOUJOURS exiger un script de construction de projet pour référencer 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/dirs ou ${env.Variable}/other/dir.

  12. NE JAMAIS autoriser un script de construction de projet à référencer TOUT avec un chemin relatif comme .\some\dirs\here ou ..\some\more\dirs, TOUJOURS utiliser des chemins absolus.

  13. NE JAMAIS autoriser un script de construction de projet à référencer TOUT en utilisant un chemin absolu qui n'a pas de répertoire racine configurable, comme C:\some\dirs\here ou \\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 minimiser 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, 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 construction 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 génération de projet vérifie chacun de ses exécutables d'outils de génération dépendants, des fichiers de bibliothèque externes et des fichiers livrables du projet dépendant, et abandonne avec un message significatif si ces fichiers n'existent pas.

  20. RÉSISTEZ à la tentation de valider N'IMPORTE QUEL fichier généré dans le contrôle de code source - aucun livrable de projet, aucune source générée, aucun document généré, 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 pour 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, ainsi que votre référentiel de contrôle de source.

  23. Mettre en place un serveur d'intégration continue (build machine) sans aucun outil de développement.

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

  25. N'utilisez PAS Maven - cela vous rendra d'abord heureux et vous fera éventuellement pleurer.

Notez que rien de tout cela n'est spécifique à Subversion, et la plupart est générique 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 à des fins d'illustration. -J'espère que vous traduirez vers votre système d'exploitation ou l'outil de votre choix.

Remarque supplémentaire concernant les solutions Visual Studio: ne les mettez pas en 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 créer/utiliser comme bon leur semble (mais pas archivés pour le contrôle de code source). Je garde un Rob.sln fichier sur mon poste de travail à partir duquel je référence mes projets en cours. Étant donné que mes projets sont tous autonomes, je peux ajouter/supprimer des projets à volonté (cela signifie pas de références de dépendance basées sur un projet).

Veuillez ne pas utiliser d'externes Subversion (ou similaire dans d'autres outils), ils sont anti-modèle et, par conséquent, inutiles.

Lorsque vous implémentez une intégration continue, ou même lorsque vous souhaitez simplement automatiser le processus de publication, créez un script pour celui-ci. Créez un script Shell unique qui: prend les paramètres du nom du projet (tels que répertoriés dans le référentiel) et du nom de la balise, crée un répertoire temporaire dans un répertoire racine configurable, vérifie la source du nom de projet et du nom de balise donnés (en construisant le URL appropriée dans le cas de Subversion) vers ce répertoire temporaire, effectue une nouvelle construction 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 "build tools". 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 que "ant-a.b.c.d.jar" après avoir été brûlé lorsque votre script de construction se casse parce que vous l'avez exécuté sans le savoir avec une version incompatible d'Ant. Ceci est particulièrement courant entre Ant 1.6.5 et 1.7.0. En général, vous voulez TOUJOURS savoir quelle version spécifique de CHAQUE composant est utilisée, y compris votre plate-forme (Java A.B.C.D) et votre outil de construction (Ant E.F.G.H). Sinon, vous finirez par rencontrer un bogue et votre premier GRAND problème sera de savoir quelles versions de vos différents composants sont impliquées. Il est tout simplement préférable de résoudre ce problème dès le départ.

92
Rob Williams

Je crois que Pragmatic Version Control using Subversion a tout ce dont vous avez besoin pour organiser votre référentiel.

3
Fabio Gomes

Nous avons configuré le nôtre pour correspondre presque exactement à ce que vous avez publié. Nous utilisons le formulaire général:

\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 ne soit 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 finissent pas dans le contrôle de code source, et j'ai toujours pensé qu'ils le devraient.

3
SqlRyan

Pourquoi tout avoir dans un seul référentiel? Pourquoi ne pas simplement avoir un référentiel séparé 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? Il suffit de le supprimer 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 ...

Je suis peut-être stupide, mais j'aime un projet par référentiel.

1
Rene Saarsoo

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 (sauf si svn: externals est plus sophistiqué que je ne l'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 devez créer à partir de cette branche ultérieurement (version QFE), elle 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 des répertoires de niveau supérieur dans votre structure), puis de les ramifier avec chaque version de la solution any.

0
C. Dragon 76

Pour ajouter au problème de chemin relatif:

Je ne suis pas sûr que ce soit un problème:
Il suffit de commander Solution1/trunk sous le répertoire nommé "Solution1", idem pour Solution2: l'objectif des "répertoires" représentant réellement les branches est de ne pas être visible une fois importé dans un espace de travail. Des chemins relatifs sont donc possibles entre 'Solution1' (en fait 'Solution1/trunk') et 'Solution2' (Solution2/trunk).

0
VonC

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

Il semble que cela soit spécifique à svn, mais ce n'est pas un problème. Une autre personne a déjà mentionné des référentiels distincts et c'est probablement la meilleure solution à laquelle je peux 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 de nombreux autres) fonctionnera correctement.

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

0
Tim

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

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

0
Casey