web-dev-qa-db-fra.com

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

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

Je mets en place un workflow pour plusieurs projets au travail, et je me demandais comment ce serait si nous adoptions cette approche un peu à l'extrême au lieu d'avoir un seul projet monolithique. J'ai rapidement réalisé qu'il y avait un potentiel de vers dans vraiment en utilisant des sous-modules.

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

  • core est autonome
  • graph dépend de core (sous-module à ./libs/core)
  • network dépend de core (sous-module à ./libs/core)
  • studio dépend de graph et network (sous-modules à ./libs/graph et ./libs/network)
  • player dépend de graph et network (sous-modules à ./libs/graph et ./libs/network)

Supposons que nous utilisons CMake et que chacun de ces projets ait des tests unitaires et tous les travaux. Chaque projet (y compris studio et player) doit pouvoir être compilé de façon autonome pour effectuer des mesures de code, des tests unitaires, etc.

La chose est, un récursif git submodule fetch, vous obtenez la structure de répertoires 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 core est cloné deux fois dans le projet studio. Mis à part cet espace disque gaspillé, j'ai un problème de système de génération car je construis core deux fois et j'obtiens potentiellement deux versions différentes de core.

Question

Comment organiser les sous-modules pour obtenir la dépendance versionnée et la version autonome sans obtenir plusieurs copies des sous-modules imbriqués courants?

Solution possible

Si la dépendance de la bibliothèque est quelque peu 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 dépendantes potentielles sont responsables de la construction avec la version de leur choix, alors Je pourrais imaginer le scénario suivant:

  • Demandez au système de génération de graph et network de leur dire où trouver core (par exemple via un chemin d'inclusion de compilateur). Définissez deux cibles de build, "autonome" et "dépendance", où "autonome" est basé sur "dépendance" et ajoute le chemin d'inclusion pour pointer vers le sous-module local core.
  • Introduisez une dépendance supplémentaire: studio sur core. Ensuite, studio construit core, définit le chemin d'inclusion vers sa propre copie du sous-module core, puis construit graph et network en mode "dépendance".

La structure de dossiers 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 une certaine magie du système de construction (je suis assez confiant que cela peut être fait avec CMake) et un peu de travail manuel de la part des mises à jour de version (la mise à jour graph pourrait également nécessiter la mise à jour core et network pour obtenir une version compatible de core dans tous les projets).

Des réflexions à ce sujet?

50
André Caron

Je suis très en retard à cette fête, mais votre question ne semble toujours pas avoir de réponse complète, et c'est un succès assez important 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, qui obtient une bizarrerie supplémentaire parce que MATLAB n'est pas compilé. Je suis tombé sur cette vidéo récemment, ce qui semble proposer une "solution". Je n'aime pas la solution, car cela signifie essentiellement de jeter des sous-modules, mais cela élimine le problème. C'est exactement comme le recommande @errordeveloper. Chaque projet n'a pas de sous-modules. Pour construire un projet, créez un super-projet pour le construire et incluez-le en tant que frère de ses dépendances.

Ainsi, votre projet de développement de graph pourrait ressembler à:

buildgraph/graph
buildgraph/core

puis votre projet de studio pourrait être:

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

Les super-projets ne sont qu'un _ CMakeLists.txt et un tas de sous-modules. Mais aucun des projets n'a de sous-modules eux-mêmes.

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

5
chadsgilbert

Je suppose que lorsque vous intégrez les sous-modules graph et network dans studio, vous devez toujours avoir la même version de core à un moment donné de l'histoire de studio. Je lierais simplement le studio/libs/core sous-module en 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

v1 et v2 sont deux versions différentes de core. graph gère la version 2, tandis que network a besoin d'un peu de travail et est bloqué à la version 1. Dans studio, les versions locales incorporées de core pointent toutes deux vers v1 pour 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/

Je valide localement ce changement et je perds la possibilité d'avoir deux versions distinctes de core à l'intérieur de studio, mais je ne crée core qu'une seule fois. Lorsque je suis prêt à passer à v2, Je peux faire :

 git submodule update # (--rebase ?)

... à l'intérieur de studio/libs/network.

1
coredump

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 liez sont toujours au même endroit en un an? Et sur cinq?

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

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

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


e.g. ext/boost, ext/cppunit

Bien que ce ne soit pas très agréable du point de vue de l'espace disque, j'apprécie la garantie que je peux vérifier chaque état enregistré tant que le dépôt est disponible beaucoup plus haut.

De plus, il y a un tas de problèmes avec les sous-modules comme décrit ici

0
Wilbert

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 que README et les scripts de construction. Il y aurait être un script de construction distinct pour chacun des packages liant ses dépendances. Sinon, vous pouvez avoir un référentiel distinct pour un package.

0
errordeveloper

Face exactement au même problème ici. Une des solutions pourrait être d'avoir un repo libs qui contiendrait core, network, graph comme sous-modules et juste des CMakeLists qui indiqueraient chacune des bibliothèques où trouver ses dépendances. Chaque application aurait désormais libs comme 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 comme applications distinctes
  • 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
0
Max