web-dev-qa-db-fra.com

Choisir entre un ou plusieurs projets dans un référentiel git?

Dans un environnement git, où nous avons modularisé la plupart des projets, nous sommes confrontés au un projet par référentiel ou plusieurs projets par référentiel problème de conception. Prenons un projet modulaire:

myProject/
   +-- gui
   +-- core
   +-- api
   +-- implA
   +-- implB

Aujourd'hui, nous avons un projet par référentiel . Il donne la liberté

  • release composants individuels
  • tag composants individuels

Mais il est également compliqué de branch composants aussi souvent que la ramification api nécessite des branches équivalentes dans core, et peut-être d'autres composants.

Étant donné que nous voulons release des composants individuels, pouvons-nous toujours obtenir la même flexibilité en utilisant une plusieurs projets par conception de référentiel .

Quelles sont les expériences et comment/pourquoi avez-vous abordé ces problèmes?

239
Johan Sjöberg

Il y a trois inconvénients majeurs à one project per repository, comme vous l'avez décrit ci-dessus. Celles-ci sont moins vraies s'il s'agit de projets vraiment distincts, mais à en juger par les changements, il faut souvent des changements à un autre, ce qui peut vraiment exagérer ces problèmes:

  1. Il est plus difficile de découvrir quand des bogues ont été introduits. Des outils comme git bisect devient beaucoup plus difficile à utiliser lorsque vous fractionnez votre référentiel en sous-référentiels. C'est possible, ce n'est pas aussi facile, ce qui signifie que la chasse aux insectes en temps de crise est beaucoup plus difficile.
  2. Le suivi de l'historique complet d'une fonction est beaucoup plus difficile. Les commandes de parcours de l'historique comme git log il suffit de ne pas afficher l'historique de manière aussi significative avec des structures de référentiel fracturées. Vous pouvez obtenir certaines sorties utiles avec des sous-modules ou des sous-arbres, ou par le biais d'autres méthodes scriptables, mais ce n'est pas la même chose que de taper tig --grep=<caseID> ou git log --grep=<caseID> et en analysant tous les commits qui vous intéressent. Votre histoire devient plus difficile à comprendre, ce qui la rend moins utile lorsque vous en avez vraiment besoin.
  3. Les nouveaux développeurs passent plus de temps à apprendre la structure du contrôle de version avant de pouvoir commencer à coder. Chaque nouveau travail nécessite des procédures de ramassage, mais la fracturation d'un référentiel de projet signifie qu'ils ont pour récupérer la structure VC en plus de l'architecture du code. D'après mon expérience, cela est particulièrement difficile pour les développeurs débutants qui viennent de boutiques plus traditionnelles et centralisées qui utilisent un seul référentiel.

En fin de compte, c'est un calcul du coût d'opportunité. Chez un ancien employeur, notre application principale était divisée en 35 sous-répertoires différents. De plus, nous avons utilisé un ensemble compliqué de scripts pour rechercher l'historique, nous assurer que l'état (c.-à-d. Les branches de production et de développement) était le même à travers eux, et les déployer individuellement ou en masse.

C'était trop; trop pour nous au moins. Les frais généraux de gestion ont rendu nos fonctionnalités moins agiles, rendu les déploiements beaucoup plus difficiles, rendu trop long l'enseignement des nouveaux développeurs, et à la fin de celui-ci, nous pouvions à peine nous rappeler pourquoi nous avons fracturé le référentiel en premier lieu. Un beau jour de printemps, j'ai dépensé 10 $ pour un après-midi de temps de calcul de cluster en EC2. J'ai remonté les dépôts avec quelques dizaines git filter-branch appels. Nous n'avons jamais regardé en arrière.

209
Christopher

Christopher a fait un très bon travail d'énumération des inconvénients d'un modèle à un projet par référentiel. Je voudrais discuter de certaines des raisons pour lesquelles vous pourriez envisager une approche à référentiels multiples. Dans de nombreux environnements dans lesquels j'ai travaillé, une approche multi-référentiels a été une solution raisonnable, mais la décision du nombre de référentiels à avoir, et où faire les coupes n'a pas toujours été facile à faire.

Dans mon poste actuel, j'ai migré un référentiel CVS géant à référentiel unique avec plus de dix ans d'histoire dans un certain nombre de référentiels git. Depuis cette décision initiale, le nombre de référentiels a augmenté (grâce aux actions d'autres équipes), au point où je pense que nous en avons plus que ce qui serait optimal. Certains nouveaux employés ont suggéré de fusionner les référentiels, mais je me suis opposé à cela. Le projet Wayland a une expérience similaire. Dans un entretien que j'ai vu récemment, ils avaient, à un moment donné, plus de 200 dépôts git, pour lesquels le responsable s'est excusé. En regardant leur site Web , je vois maintenant qu'ils sont à 5, ce qui semble raisonnable. Il est important de noter que la jonction et la division de référentiels est une tâche gérable, et il est normal d'expérimenter (dans des limites raisonnables).

Alors, quand pourriez-vous vouloir plusieurs référentiels?

  1. Un référentiel unique serait trop volumineux pour être efficace.
  2. Vos référentiels sont faiblement couplés ou découplés.
  3. Un développeur n'a généralement besoin que d'un ou d'un petit sous-ensemble de vos référentiels pour se développer.
  4. Vous souhaitez généralement développer les référentiels de manière indépendante et n'avez besoin de les synchroniser qu'occasionnellement.
  5. Vous souhaitez encourager davantage de modularité.
  6. Différentes équipes travaillent sur différents référentiels.

Les points 2 et 3 ne sont significatifs que si le point 1 tient. En fractionnant nos référentiels, j'ai considérablement réduit les retards subis par nos collègues hors site, réduit la consommation de disque et amélioré le trafic réseau.

4 et 5 sont plus subtils. Lorsque vous divisez le référentiel d'un client et d'un serveur, cela rend plus coûteuse la coordination des modifications entre le code client et le code serveur. Cela peut être positif, car cela encourage une interface découplée entre les deux.

Même avec les inconvénients des projets multi-référentiels, beaucoup de travail respectable est fait de cette façon - Wayland et boost viennent à l'esprit. Je ne crois pas qu'un consensus sur les meilleures pratiques ait encore évolué, et un certain jugement est nécessaire. Des outils pour travailler avec plusieurs référentiels (git-subtree, git-submodule et autres) sont toujours en cours de développement et d'expérimentation. Mon conseil est d'expérimenter et d'être pragmatique.

70
Spacemoose

Comme nous utilisons GitHub, nous avons en fait plusieurs projets dans un référentiel mais assurez-vous que ces projets/modules sont correctement modularisés (nous utilisons les conventions -api et -core + Maven + la vérification statique et d'exécution et pourraient même aller à OSGi un jour pour démarrer).

Sur quoi économise-t-il? Eh bien, nous n'avons pas à émettre plusieurs demandes d'extraction si nous modifions quelque chose de petit sur plusieurs projets. Les problèmes et le wiki sont centralisés, etc.

Nous traitons toujours chaque module/projet comme un projet indépendant approprié et les construisons et les intégrons séparément dans notre serveur CI, etc.

51
Martijn Verburg

Pour moi, la principale différence dans l'utilisation d'un ou plusieurs référentiels réside dans les réponses aux questions suivantes:

  • Les multiples pièces développées par la même équipe, ont-elles le même cycle de sortie, le même client? Il y a alors moins de raisons de diviser le référentiel.
  • Les parties multiples hautement dépendent-elles les unes des autres? Il n'est donc pas très judicieux de diviser le modèle, le contrôleur et l'interface utilisateur (même lorsqu'ils sont différents), en raison de la forte dépendance les uns des autres. Mais si 2 parties n'ont qu'une petite dépendance, qui est implémentée par une interface stable qui n'est modifiée que toutes les quelques années, il serait donc sage de diviser les 2 parties en 2 référentiels.

À titre d'exemple, j'ai une petite application (client uniquement), qui vérifie la "qualité" d'un référentiel Subversion. Il y a l'implémentation de base, qui pourrait être démarrée à partir de la ligne de commande, et fonctionne bien avec Java 6. Mais j'ai commencé à implémenter une interface utilisateur, qui utilise JavaFX dans le cadre de Java 8. J'ai donc divisé les 2 et créé un deuxième référentiel (avec un deuxième processus de construction), avec un calendrier différent, ...

J'aime les réponses ci-dessus (les a votées), mais je pense qu'elles ne sont pas toute l'histoire vraie. Je voulais donc également ajouter les arguments pour fractionner les référentiels. Donc la vraie réponse (quand se séparer) peut être quelque part au milieu ...

24
mliebelt

Il se pourrait que git-subtree (voir blog Atlassian , blog moyen , ou lien noya ) serait un bon ajustement pour ce que vous avez. Ainsi, chacun de vos projets de niveau supérieur utiliserait un ensemble de sous-arborescences dans des versions éventuellement différentes.

D'après votre exemple, les référentiels doivent être configurés en fonction de leur interdépendance. Tout le raisonnement sur la conception de MicroServices et de Domain Driven Design s'applique ici: dans certains cas, le code en double est acceptable, travaillez avec des interfaces, ne brisez pas la compatibilité à moins que vous ne l'ayez vraiment, etc.

Maintenant, à mon avis, une interface utilisateur devrait être indépendante du backend. Un référentiel de projet d'interface utilisateur doit donc généralement contenir le code d'interface utilisateur et le contrôleur client. Le contrôleur client se connectera aux contrôleurs de service de manière abstraite. Ils utiliseront une abstraction client/api de service qui est versionnée séparément du service, afin qu'un service puisse être mis à jour sans casser le (s) client (s) (il peut y avoir plusieurs clients différents).

Un service lui-même doit donc être son propre référentiel. À mon avis, le service n'est qu'une enveloppe d'une logique métier à point de vérité unique. Par conséquent, la logique métier doit généralement être distincte de la technologie de service qui l'héberge. D'un autre côté, l'implémentation du référentiel est généralement si étroitement liée à la logique métier, qu'elle pourrait être intégrée dans le même référentiel. Mais même là, votre kilométrage peut varier.

Bien sûr, les projets simples qui ne changeront probablement pas beaucoup en termes de technologie ou de prise en charge de plusieurs piles, où toutes les interfaces utilisateur peuvent être hébergées à partir de la même source que le backend et les services backend ne sont généralement utilisés que par ce même client, peuvent bénéficier de plus des référentiels étroitement intégrés.

Dans ce cas, vous seriez probablement d'accord avec le simple fait d'avoir la verticale complète dans un référentiel, et de vous concentrer uniquement sur le fait que vos domaines fonctionnels sont correctement autonomes dans leur propre référentiel. Vous avez alors toujours la plupart des avantages des référentiels plus petits et peu de frais généraux sinon.

1
Arwin