Organisation des référentiels Git avec des sous-modules imbriqués communs


50

Je suis un grand fan des sous-modules Git . J'aime pouvoir suivre une dépendance avec sa version, de sorte que vous puissiez revenir à une version précédente de votre projet et disposer de la version correspondante de la dépendance pour construire en toute sécurité et proprement. De plus, il est plus facile de publier nos bibliothèques sous forme de projets open source car l'historique des bibliothèques est séparé de celui des applications qui en dépendent (et qui ne seront pas en open source).

J'établis un flux de travail pour plusieurs projets au travail, et je me demandais ce qui se passerait si nous adoptions cette approche un peu extrême au lieu de n'avoir qu'un seul projet monolithique. J'ai vite compris qu'il y avait un potentiel de ver à utiliser réellement des sous-modules.

Supposons une paire d'applications: studioet player, et des bibliothèques dépendantes core, graphet network, où les dépendances sont les suivantes:

  • core est autonome
  • graphdépend de core(sous-module à ./libs/core)
  • networkdépend de core(sous-module à ./libs/core)
  • studiodépend de graphet network(sous-modules à ./libs/graphet ./libs/network)
  • playerdépend de graphet network(sous-modules à ./libs/graphet ./libs/network)

Supposons que nous utilisions CMake et que chacun de ces projets comporte des tests unitaires et tous les travaux. Chaque projet (y compris studioet player) doit pouvoir être compilé de manière autonome pour effectuer des métriques de code, des tests unitaires, etc.

La chose est, un récursif git submodule fetch, alors vous obtenez la structure de répertoire suivante:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/graph/
studio/libs/graph/libs/         (sub-module depth: 2)
studio/libs/graph/libs/core/
studio/libs/network/
studio/libs/network/libs/       (sub-module depth: 2)
studio/libs/network/libs/core/

Notez que coredeux fois cloné dans le studioprojet. Outre ce gaspillage d'espace disque, j'ai un problème de système de génération, car je construis coredeux fois et j'obtiens potentiellement deux versions différentes de core.

Question

Comment organiser des sous-modules de manière à obtenir la dépendance versionnée et la génération autonome sans obtenir plusieurs copies des sous-modules imbriqués courants?

Solution possible

Si la dépendance de la bibliothèque est en quelque sorte une suggestion (c'est-à-dire d'une manière "connue pour fonctionner avec la version X" ou "seule la version X est officiellement prise en charge") et que les applications ou bibliothèques potentiellement dépendantes sont responsables de la construction avec la version de leur choix, Je pourrais imaginer le scénario suivant:

  • Demandez au système de construction de graphet networkdites-leur où trouver core(par exemple, via un chemin d’inclusion du compilateur). Définissez deux cibles de construction, "autonome" et "dépendance", où "autonome" est basé sur "dépendance" et ajoute le chemin d'inclusion pour pointer vers le coresous-module local .
  • Introduisez une dépendance supplémentaire: studioon core. Ensuite, studiobuilds core, définit le chemin d’inclusion sur sa propre copie du coresous-module, puis construit graphet networken mode "dépendance".

La structure de dossier résultante ressemble à ceci:

studio/
studio/libs/                    (sub-module depth: 1)
studio/libs/core/
studio/libs/graph/
studio/libs/graph/libs/         (empty folder, sub-modules not fetched)
studio/libs/network/
studio/libs/network/libs/       (empty folder, sub-modules not fetched)

Cependant, cela nécessite un peu de magie du système de construction (je suis assez confiant, cela peut être fait avec CMake) et un peu de travail manuel de la part des mises à jour de version (la mise à jour graphpeut également nécessiter une mise à jour coreet networkobtenir une version compatible de coretous les projets) .

Des idées à ce sujet?


Notez que ce problème n'est pas spécifique à cmake: il existe pour tout système de construction, y compris aucun système! (c'est-à-dire qu'il est prévu que le super-projet ajoute simplement les sources de la bibliothèque; ce qui inclut les bibliothèques avec en-tête uniquement)
MM

Réponses:


5

Je suis très en retard pour ce parti, mais votre question ne semble toujours pas avoir de réponse complète, et c'est un succès assez connu de Google.

J'ai exactement le même problème avec C ++ / CMake / Git / Submodules et j'ai un problème similaire avec MATLAB / Git / Submodules, ce qui génère un surcroît de bizarrerie car MATLAB n'est pas compilé. Je suis tombé sur cette vidéo récemment, qui semble proposer une "solution". Je n'aime pas la solution, parce que cela signifie essentiellement de jeter des sous-modules, mais cela élimine le problème. C'est exactement ce que @errordeveloper recommande. Chaque projet n'a pas de sous-modules. Pour construire un projet, créez un super-projet et intégrez-le en tant que frère de ses dépendances.

Votre projet de développement graphpourrait donc ressembler à:

buildgraph/graph
buildgraph/core

et ensuite votre projet de studio pourrait être:

buildstudio/studio
buildstudio/graph
buildstudio/network
buildstudio/core

Les super-projets ne sont que CMakeLists.txtdes sous-modules principaux. Mais aucun des projets n’a de sous-modules eux-mêmes.

Le seul coût que je perçois pour cette approche est la prolifération de "super-projets" triviaux qui sont uniquement dédiés à la construction de vos vrais projets. Et si quelqu'un met la main sur l'un de vos projets, il n'existe pas de moyen facile de savoir sans trouver également le super-projet quelles sont ses dépendances. Cela pourrait le rendre vraiment moche sur Github, par exemple.


1

Je suppose que lorsque vous intégrez les deux graphet les networksous - modules dans studio, vous devez toujours avoir la même version de coreà un moment donné dans l'histoire de studio. Je voudrais simlink le studio/libs/coresous - module dans studio/libs/{graph,network}/libs.

Mise à jour:

J'ai créé plusieurs référentiels avec les dépendances que vous avez indiquées:

./core      <--- (v2)
./graph
./graph/libs
./graph/libs/core  <--- (v2)
./graph/.gitmodules
./network
./network/libs
./network/libs/core  <--- (v1)
./network/.gitmodules
./studio
./studio/libs
./studio/libs/graph
./studio/libs/graph/libs
./studio/libs/graph/libs/core <--- (v1)
./studio/libs/graph/.gitmodules
./studio/libs/network
./studio/libs/network/libs
./studio/libs/network/libs/core  <--- (v1)
./studio/libs/network/.gitmodules
./studio/studio
./studio/.gitmodules

v1et v2sont deux versions différentes de core. graphgère la version 2, alors que networknécessite un peu de travail et est bloqué à la version 1. Dans studio, les versions locales incorporées des coredeux points à v1pour avoir un programme de travail. Maintenant, en dehors de la perspective de construction, tout fonctionne bien avec les sous-modules.

Je peux maintenant supprimer le répertoire suivant:

./studio/libs/network/libs/core

Et remplacez-le par un lien symbolique:

./studio/libs/network/libs/core@ -> ../../graph/libs/core/

J'engage localement ce changement et perd la possibilité d'avoir deux versions distinctes de coreinside studio, mais je ne construis corequ'une seule fois. Quand v2je suis prêt à passer à , je peux faire:

 git submodule update # (--rebase ?)

... dans studio / libs / network.


L'idée de lien symbolique m'a traversé l'esprit, mais c'est une non-solution. Si vous vous connectez de graph/libs/corel'extérieur, vous n'utilisez pas le sous-module. Si vous vous connectez studio/libs/coreà l'une des bibliothèques du sous-module, laquelle choisissez-vous graphou network? De plus, que se passe-t-il quand il y a trois couches ou plus de profondeur? Enfin, que se passe-t-il si corepeut être une gamme de révisions. Il n'est pas évident que vous souhaitiez créer un lien vers l'une ou l'autre version et coreque vous l' utilisiez. graphnetwork
André Caron

"lequel choisis-tu ?" : coreserait un sous-module extrait de la corebibliothèque d' origine , mis à jour vers une version compatible à la fois graphet network(vous devez choisir celle qui convient). Les liens symboliques seraient ajoutés dans les sous graph- networkmodules locaux et (non récupérés).
Coredump

1
Les liens symboliques que vous proposez d’ajouter graphet networkpointeraient en dehors de leur propre référentiel (par exemple, ailleurs dans le studioprojet). Comment savent-ils quand utiliser leur propre sous-module et quand utiliser le lien symbolique? Peut-être devriez-vous ajouter un exemple pour illustrer votre pensée.
André Caron

0

Je voudrais l'aplatir pour avoir une profondeur de sous-module d'un seul et avoir un référentiel qui contiendrait tous les modules en tant que sous-modules et rien d'autre en dehors de README et des scripts de construction. Il y aurait un script de construction séparé pour chacun des paquets reliant ses dépendances. Sinon, vous pouvez avoir un référentiel séparé pour un package.


1
Je ne suis pas sûr que ce soit clair dans mon message, mais j'ai plusieurs applications qui dépendent des mêmes bibliothèques et je ne veux pas dupliquer les scripts de construction des bibliothèques pour toutes les applications.
André Caron

3
Vous devriez développer votre réponse pour montrer comment elle résout les différents problèmes. Je ne sais pas exactement comment vous liez les dépendances, étant donné que, selon le contexte, les bibliothèques dépendantes ne se trouvent pas au même endroit.
André Caron

0

Je n'utiliserais pas de sous-modules.

C'est tentant, comme c'était le cas avec svn-externals. Cependant, pouvez-vous être sûr que tous les projets que vous associez sont toujours au même endroit au cours d'une année? Qu'en est-il dans cinq?

Par conséquent, je copie simplement toutes les dépendances requises dans mon projet. Cela signifie que tant que mon rapport est valide, je peux vérifier l'état exact.

Fondamentalement, j'ai une structure de dossier comme suit:

myproject/... [sources etc]
ext/ [third-party dependencies]


e.g. ext/boost, ext/cppunit

Bien que cela ne soit pas très intéressant du point de vue de l'espace disque, j'apprécie de pouvoir vérifier chaque état enregistré tant que le référentiel est disponible bien plus haut.

En outre, il existe toute une série de problèmes avec les sous-modules décrits ici


Je suis sûr qu'ils se trouvent au bon endroit car je les conserve tous :-) De plus, faites attention à la copie de projets en raison des conditions de redistribution.
André Caron

OK, cela réduit le problème. Et les licences: Oui, il faut faire attention, mais c'est un problème complètement différent.
Wilbert

0

Face exactement au même problème ici. L' une des solutions pourrait être d'avoir une pension libsqui détiendrait core, network, graphcomme et seulement CMakeLists sous - modules qui raconterait chacun des libs où trouver ses dépendances. Chaque application aurait maintenant libscomme sous-module et n'utiliserait que les bibliothèques nécessaires.

Le test de chaque bibliothèque peut être configuré de 2 manières:

  • Avoir core_testing, graph_testing, network_testing en tant qu'applications séparées
  • Déployer des bibliothèques testées sur des serveurs de test et les trouver lors de l'exécution de tests à l'aide de cmake

Est-ce que cela ne rend pas toutes les bibliothèques disponibles à toutes les autres bibliothèques?
André Caron

Par défaut, oui. Mais cela pourrait être décidé dans des listes de compilation au niveau de la bibliothèque. Si graphvous n'avez pas besoin de savoir sur network- ne transmettez pas les networkéléments liés au graphsous
Max
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.