git - para - submodulos en diseño
Git anidados submódulos y dependencias (6)
Digamos que tengo cuatro proyectos llamados Core , A , B , Super . El árbol de dependencias es así:
Super ---> Core
|-> A -> Core
|-> B -> Core
Quiero que cada proyecto sea independiente, es decir, quiero poder extraer y compilar cada proyecto por sí mismo (cada uno con sus dependencias, por supuesto).
Pensé en asignar cada proyecto a un repositorio y luego referir dependencias con submódulos, pero veo los siguientes problemas con ese enfoque:
- Cuando visite Super con todas sus dependencias, terminaré con tres copias de Core .
- Dado que los submódulos son totalmente independientes, cada una de estas tres copias podría estar apuntando a diferentes revisiones de Core y eso sería un desastre.
Entonces ... ¿Me estoy perdiendo algo? ¿Entendí mal los submódulos de Git o los utilicé mal? ¿Hay alguna otra solución a este problema (que no sea recurrir a dependencias binarias)?
Acaba de descubrir la falta de dependencias anuladas con los submódulos de Git:
Si Super depende de Core, su dependencia de Core debe "anular" las que A y B tienen con Core.
La única manera de emular eso sería crear tu proyecto Súper como lo hiciste,
y para eliminar el submódulo Núcleo de A y B.
(lo que significa que Super depende ahora de A ''y B'', A ''siendo A sin Núcleo, B'' siendo B sin Núcleo)
Creo que el problema aquí es un desajuste entre el diseño de Git y el problema que está buscando resolver.
Git es bueno para hacer un seguimiento de Trees. Las relaciones de dependencia entre proyectos pueden (y probablemente lo hagan) formar un Gráfico. Un árbol es un gráfico, pero un gráfico no es necesariamente un árbol. Dado que su problema es cómo representar efectivamente un gráfico, un árbol no es la mejor herramienta para el trabajo.
Aquí hay un enfoque que podría funcionar:
Un proyecto git tiene un directorio .gitmodules donde registra "sugerencias" que indican de qué proyectos puede depender una confirmación, dónde se pueden encontrar y qué ruta dentro del proyecto se espera que se inserten. ( http://osdir.com/ml/git/2009-04/msg00746.html )
Puede agregar una secuencia de comandos que lea esta información de un conjunto de proyectos, mapee las sugerencias encontradas en el archivo .gitmodules de cada proyecto en las ubicaciones del sistema de archivos donde se colocaron dichos proyectos y luego agregue enlaces simbólicos de las rutas donde git espera para ver los submódulos en las ubicaciones reales del sistema de archivos de los respectivos proyectos.
Este enfoque usa enlaces simbólicos para salir del molde Árbol y construir un Gráfico. Si grabamos los enlaces directamente en los repositorios git, tendríamos rutas relativas específicas para nuestra configuración local registradas en los proyectos individuales, y los proyectos no serían "totalmente independientes" como usted quería. Por lo tanto, la secuencia de comandos para construir dinámicamente los enlaces simbólicos.
Estoy pensando que este enfoque podría interferir con Git de maneras no deseadas, ya que hemos tomado caminos donde espera encontrar una cosa, y en su lugar, ponemos algo más. Tal vez podríamos .gitignore las rutas de enlace simbólico. Pero ahora estamos escribiendo esos caminos dos veces y violando DRY. En este punto, también nos hemos alejado bastante de pretender usar submódulos. Podríamos registrar las dependencias en otro lugar en cada proyecto, y dejar el archivo .gitmodules para las cosas que git espera. Así que crearemos nuestro propio archivo, digamos, .dependencias, y cada proyecto puede indicar sus dependencias allí. Nuestro script se verá allí y luego irá y construirá sus enlaces simbólicos.
Hmm, creo que acabo de describir un sistema de administración de paquetes ad-hoc, con su propio formato de paquete liviano :)
La sugerencia de megamic me parece un buen uso de los submódulos de git. Solo tratamos de hacer un seguimiento de un conjunto aquí en lugar de un gráfico, y un conjunto encaja fácilmente en un árbol. Un árbol de un nivel de profundidad es esencialmente un nodo padre y un Conjunto de nodos secundarios.
Como señaló, eso no resuelve por completo el problema planteado en su pregunta. Podemos dividir dos tipos distintos de información de "esto funciona con eso" en la que probablemente estamos interesados: 1. Una declaración de una versión de un proyecto (presumiblemente por el autor del proyecto) que dice "Necesito la versión X del proyecto Y" 2 Una declaración utilizada por tu propia configuración de compilación diciendo "He probado con éxito todo nuestro sistema usando este conjunto de versiones de proyectos"
la respuesta de megamic resuelve (2) pero para (1) todavía queremos que los proyectos nos digan cuáles son sus dependencias. Entonces podemos usar la información de (1) para calcular los conjuntos de versiones que terminaremos registrando como (2). Este es un problema bastante complejo para garantizar su propia herramienta, lo que nos lleva de vuelta a los sistemas de administración de paquetes :)
Hasta donde yo sé, la mayoría de las buenas herramientas de administración de paquetes están hechas para usuarios de un idioma o sistema operativo específico. Ver Bundler para paquetes de ''gemas'' en el mundo de ruby y apto para paquetes ''.deb'' en el mundo de Debian.
Si alguien sabe de una buena solución neutra para el lenguaje y neutral con el sistema operativo que sea adecuada para proyectos de programación ''polyglot'' ( http://blog.heroku.com/archives/2011/8/3/polyglot_platform/ ), ¡Estaría muy interesado! Debería publicar eso como una pregunta.
Creo que puede gestionar la coherencia de esta manera: defina una rama de "referencia" o una serie de etiquetas con el mismo nombre en todas sus bibliotecas "Core" (nota: solo hay una biblioteca "Core" en su ejemplo). A continuación, solicite a los desarrolladores de subproyectos (A, B, ...) que actualicen regularmente a la versión de referencia de "Core" tan pronto como puedan.
Antes de ejecutar una compilación, compruebe fácilmente que "Core (s)" se usa de forma consistente en A, B, C, ... ejecutando estos tres comandos en un proceso limpio, recursivo, "Super", de nivel superior:
# 1. Switch to the reference version (= "Force" consistency where need be)
git submodule foreach --recursive ''git checkout [origin/]reference || true''
# 2a. Show which inconsistencies you just forced; terse output
git status -s; git submodule foreach --recursive git status -s 2>/dev/null
# 2b. Same but verbose output
git submodule; git submodule foreach --recursive git submodule
# 3. Switch back to versions individually defined by sub-projects
git submodule update --recursive
El comando "Terse output" 2a anterior resalta qué sub-proyecto (s) no están usando la versión "de referencia" de Core.
Puede ampliar fácilmente el enfoque para mostrar diffs, forzar actualizaciones o hacer cualquier otra cosa que desee.
Los repositorios git deben ser bastante atómicos en la forma en que cada repositorio es una entidad independiente para un propósito específico. ¿Cuál es el propósito del superproyecto además de combinar los proyectos A y B? Si no hay nada único (es decir, archivos que no están en A, B o Core), entonces es bastante redundante.
EDITAR: Debido a que los submódulos de git son especialmente dolorosos en un lugar en el que trabajé, creamos nuestro propio sistema de dependencia que rastrea los repositorios dependientes a través de archivos de texto. Lo configuramos para que siempre rastree la cabeza de una rama, no un compromiso en particular.
Pudimos configurar todos nuestros proyectos como si fueran parte del proyecto Super de esta manera:
Super
|-A
|-B
|-Core
Los proyectos se referirán unos a otros usando rutas relativas, por ejemplo ../A/include.h
. Verificando el repositorio A no funcionará, tendrías que crear otro repositorio "super" para trabajar solo en A:
AWorking
|-A
|-Core
EDITAR Otra razón de este comportamiento en git es que no puede rastrear elementos que están por encima del directorio de repositorio raíz (es decir, encima de la carpeta que contiene la carpeta .git), lo cual sería definitivamente necesario si desea sus superproyectos y subproyectos. consulte los mismos repositorios.
No trataría de mapear un árbol de dependencias con submódulos, por las razones que ya ha descubierto.
Los submódulos rastrean una revisión dada de una rama determinada, por lo que son útiles para dar una instantánea de un conjunto consistente de módulos.
Por lo tanto, si su proyecto requiere un determinado conjunto de versiones de diferentes módulos para ser rastreados como una unidad, puede agruparlos como submódulos. A continuación, puede etiquetar diferentes conjuntos de módulos en diferentes versiones, para proporcionar un historial del proyecto, donde cada etiqueta muestra qué versiones de qué módulos son compatibles en un momento determinado.
tags/
release1/
|-> [email protected]
|-> [email protected]
|-> [email protected]
release2/
|-> [email protected]
|-> [email protected]
|-> [email protected]
Al menos así como los entiendo, aunque como la mayoría de las cosas con Git, probablemente hay mucho más que eso. En términos de administración de dependencias, todo lo que puedo decir es encontrar otra manera, no es para lo que se diseñó Git con o sin submódulos, tal como lo entiendo.
Una pequeña tarea de utilidad convirtiendo los submódulos compartidos en clones usando enlaces duros podría funcionar.
Puede leer mi solución completa aquí: https://.com/a/10265084/84283