Organizar repositorios de Git con submódulos anidados comunes

48

Soy un gran fan de submódulos Git . Me gusta poder rastrear una dependencia junto con su versión, para que pueda revertir a una versión anterior de su proyecto y tener la versión correspondiente de la dependencia para construir de forma segura y limpia. Además, es más fácil lanzar nuestras bibliotecas como proyectos de código abierto, ya que el historial de las bibliotecas es independiente del de las aplicaciones que dependen de ellas (y que no serán de código abierto).

Estoy configurando el flujo de trabajo para múltiples proyectos en el trabajo, y me preguntaba cómo sería si tomáramos este enfoque un poco extremo en lugar de tener un solo proyecto monolítico. Rápidamente me di cuenta de que existe una lata potencial de gusanos en realmente usando sub-módulos.

Suponiendo un par de aplicaciones: studio y player , y bibliotecas dependientes core , graph y network , donde las dependencias son las siguientes:

  • core es independiente
  • graph depende de core (submódulo en ./libs/core )
  • network depdends en core (submódulo en ./libs/core )
  • studio depende de graph y network (submódulos en ./libs/graph y ./libs/network )
  • player depende de graph y network (submódulos en ./libs/graph y ./libs/network )

Supongamos que estamos usando CMake y que cada uno de estos proyectos tiene pruebas unitarias y todos los trabajos. Cada proyecto (incluidos studio y player ) debe poder compilarse de forma independiente para realizar métricas de código, pruebas de unidad, etc.

La cosa es, un git submodule fetch recursivo, luego obtienes la siguiente estructura de directorio:

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/

Observe que core se clona dos veces en el proyecto studio . Aparte de esta pérdida de espacio en el disco, tengo un problema en el sistema de compilación porque estoy compilando core dos veces y potencialmente obtengo dos versiones diferentes de core .

Pregunta

¿Cómo organizo los submódulos para obtener la dependencia versionada y la compilación independiente sin obtener múltiples copias de submódulos anidados comunes?

Posible solución

Si la dependencia de la biblioteca es algo así como una sugerencia (es decir, en una forma "se sabe que funciona con la versión X" o "se admite oficialmente la única versión X") y las aplicaciones o bibliotecas dependientes potenciales son responsables de construir con cualquier versión como, entonces podría imaginar el siguiente escenario:

  • Haga que el sistema de compilación para graph y network les diga dónde encontrar core (por ejemplo, a través de una ruta de inclusión del compilador). Defina dos objetivos de compilación, "independiente" y "dependencia", donde "independiente" se basa en "dependencia" y agrega la ruta de inclusión para apuntar al sub-módulo core local.
  • Introduzca una dependencia adicional: studio en core . Luego, studio genera core , establece la ruta de inclusión a su propia copia del submódulo core , luego genera graph y network en el modo "dependencia".

La estructura de carpetas resultante se ve así:

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)

Sin embargo, esto requiere algo de magia en el sistema de compilación (estoy bastante seguro de que esto se puede hacer con CMake) y un poco de trabajo manual por parte de las actualizaciones de la versión (la actualización de graph también puede requerir la actualización de core y network para obtener una versión compatible de core en todos los proyectos).

¿Alguna idea sobre esto?

    
pregunta André Caron 17.10.2011 - 17:37

5 respuestas

5

Llego muy tarde a esta fiesta, pero tu pregunta aún no parece tener una respuesta completa, y es un éxito bastante importante de google.

Tengo exactamente el mismo problema con C ++ / CMake / Git / Submodules y tengo un problema similar con MATLAB / Git / Submodules, que tiene algunas rarezas adicionales porque MATLAB no está compilado. Encontré este video recientemente, que parece proponer una "solución". No me gusta la solución, porque esencialmente significa tirar los submódulos, pero elimina el problema. Es tal como lo recomienda @errordeveloper. Cada proyecto no tiene submódulos. Para crear un proyecto, cree un superproyecto para construirlo e inclúyalo como hermano a sus dependencias.

Por lo tanto, su proyecto para desarrollar graph podría tener el siguiente aspecto:

buildgraph/graph
buildgraph/core

y luego tu proyecto para estudio podría ser:

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

Los superproyectos son solo un CMakeLists.txt principal y un montón de submódulos. Pero ninguno de los proyectos tiene submódulos.

El único costo que veo con este enfoque es la proliferación de "superproyectos" triviales que están dedicados a la construcción de sus proyectos reales. Y si alguien se apodera de uno de sus proyectos, no hay una manera fácil de decirlo sin encontrar también el superproyecto, cuáles son sus dependencias. Eso podría hacer que se sienta realmente feo en Github, por ejemplo.

    
respondido por el chadsgilbert 28.07.2016 - 15:18
1

Supongo que cuando integras los submódulos tanto graph como network en studio , siempre debes tener la misma versión de core en un momento dado en el historial de studio . Me gustaría enlazar el submódulo studio/libs/core en studio/libs/{graph,network}/libs .

Actualización:

Creé múltiples repositorios con las dependencias que declaraste:

./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 y v2 son dos versiones diferentes de core . graph maneja la versión 2, mientras que network necesita algo de trabajo y está atascado en la versión 1. En studio , las versiones locales incrustadas de core apuntan a v1 para tener un programa que funcione. Ahora, aparte de la perspectiva de compilación, todo funciona bien con los submódulos.

Ahora puedo eliminar el siguiente directorio:

./studio/libs/network/libs/core

Y reemplácelo con un enlace simbólico:

./studio/libs/network/libs/[email protected] -> ../../graph/libs/core/

Comprometo localmente este cambio y pierdo la capacidad de tener dos versiones separadas de core dentro de studio , pero solo compilo core una vez. Cuando esté listo para actualizar a v2 , puedo hacerlo:

 git submodule update # (--rebase ?)

... dentro de studio / libs / network.

    
respondido por el coredump 10.11.2011 - 22:11
0

Lo aplastaría para tener una profundidad de sub-módulo de solo uno y un repositorio que contendría a todos los módulos como sub-módulos y nada más aparte de README y los scripts de compilación. Habría una secuencia de comandos de compilación separada para cada uno de los paquetes que vinculan sus dependencias. De lo contrario, puede tener un repositorio separado para un paquete.

    
respondido por el errordeveloper 17.10.2011 - 22:34
0

No usaría submódulos.

Es tentador, como solía ser el caso con svn-externals. Sin embargo, ¿puede estar seguro de que todos los proyectos que vincula se encuentran en el mismo lugar en un año? ¿Y en cinco?

Por lo tanto, simplemente estoy copiando todas las dependencias requeridas en mi proyecto. Esto significa que mientras mi repo sea válido, puedo verificar el estado exacto.

Básicamente, tengo una estructura de carpetas de la siguiente manera:

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


e.g. ext/boost, ext/cppunit

Aunque esto no es muy bueno desde la perspectiva del espacio en disco, valoro la garantía de que puedo revisar todos los estados registrados siempre que el repositorio esté disponible mucho más alto.

Además, hay muchos problemas con los submódulos, tal como se describe aquí

    
respondido por el Wilbert 30.04.2013 - 14:08
0

Enfrentando exactamente el mismo problema aquí. Una de las soluciones podría ser tener un repo libs que contendría core , network , graph como submódulos y solo CMakeLists que le diría a cada una de las librerías dónde encontrar sus dependencias. Cada aplicación ahora tendría libs como submódulo y usaría solo las librerías necesarias.

La prueba de cada lib puede configurarse de dos maneras:

  • Tiene core_testing, graph_testing, network_testing como aplicaciones separadas
  • Implemente las bibliotecas probadas en los servidores de prueba y búsquelos mientras ejecuta pruebas usando cmake
respondido por el Max 24.12.2015 - 15:54

Lea otras preguntas en las etiquetas