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 autonomegraph
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
.
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?
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:
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
.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?
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.
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.
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
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.
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: