Estamos haciendo proyectos, pero reutilizamos mucho código entre los proyectos y tenemos muchas bibliotecas que contienen nuestro código común. A medida que implementamos nuevos proyectos, encontramos más formas de factorizar código común y ponerlo en bibliotecas. Las bibliotecas dependen unas de otras, y los proyectos dependen de las bibliotecas. Cada proyecto, y todas las bibliotecas utilizadas en ese proyecto, deben usar la misma versión de todas las bibliotecas a las que se refieren. Si lanzamos una pieza de software tendremos que corregir errores y tal vez agregar nuevas funciones durante muchos años, a veces durante décadas. Tenemos alrededor de una docena de bibliotecas, los cambios a menudo abarcan más de dos, y varios equipos trabajan en varios proyectos en paralelo, realizando cambios concurrentes en todas estas bibliotecas.
Recientemente cambiamos a git y configuramos repositorios para cada biblioteca y cada proyecto. Usamos stash como un repositorio común, hacemos cosas nuevas en las ramas de características, luego hacemos solicitudes de extracción y las fusionamos solo después de la revisión.
Muchos de los problemas con los que tenemos que lidiar en los proyectos requieren que hagamos cambios en varias bibliotecas y el código específico del proyecto. Estos a menudo incluyen cambios en las interfaces de la biblioteca, algunos de los cuales son incompatibles. (Si cree que esto suena sospechoso: interactuamos con el hardware y ocultamos hardware específico detrás de las interfaces genéricas. Casi cada vez que integramos el hardware de otro proveedor nos encontramos con casos en los que nuestras interfaces actuales no se anticipaban, por lo que tenemos que refinarlos). ejemplo, imagine un proyecto P1
usando las bibliotecas L1
, L2
y L3
. L1
también usa L2
y L3
, y L2
usa L3
también. El gráfico de dependencia se ve así:
<-------L1<--+
P1 <----+ ^ |
<-+ | | |
| +--L2 |
| ^ |
| | |
+-----L3---+
Ahora imagine que una característica para este proyecto requiere cambios P1
y L3
que cambia la interfaz de L3
. Ahora agregue proyectos P2
y P3
en la mezcla, que también se refieren a estas bibliotecas. No podemos permitirnos cambiarlos a la nueva interfaz, ejecutar todas las pruebas e implementar el nuevo software. Entonces, ¿cuál es la alternativa?
- implementar la nueva interfaz en
L3
- hacer una solicitud de extracción
L3
y esperar la revisión - fusionar el cambio
- crear una nueva versión de
L3
- comience a trabajar en la función
P1
haciendo referencia aL3
la nueva versión, luego implemente la función enP1
la rama de funciones - hacer una solicitud de extracción, revisarla y fusionarla
(Me he dado cuenta de que se me olvidó para cambiar L1
y L2
para la nueva versión. Y yo no sé ni dónde pegar esto en, ya que tendría que hacerse en paralelo con P1
...)
Este es un proceso tedioso, propenso a errores y muy largo para implementar esta función, requiere revisiones independientes (lo que hace que sea mucho más difícil de revisar), no se escala en absoluto y es probable que nos saque del negocio porque se estancan tanto en el proceso que nunca hacemos nada.
Pero, ¿cómo empleamos la ramificación y el etiquetado para crear un proceso que nos permita implementar nuevas funciones en nuevos proyectos sin demasiados gastos generales?
Respuestas:
Es un poco poner lo obvio aquí, pero quizás valga la pena mencionarlo.
Por lo general, los repositorios de git se adaptan por lib / proyecto porque tienden a ser independientes. Actualizas tu proyecto y no te importa el resto. Otros proyectos que dependen de él simplemente actualizarán su lib cuando lo consideren conveniente.
Sin embargo, su caso parece altamente dependiente de componentes correlacionados, por lo que una característica generalmente afecta a muchos de ellos. Y todo tiene que ser empaquetado como un paquete. Dado que la implementación de una función / cambio / error a menudo requiere adaptar muchas bibliotecas / proyectos diferentes a la vez, quizás tenga sentido ponerlos a todos en el mismo repositorio.
Hay fuertes ventajas / inconvenientes en esto.
Ventajas:
Inconvenientes:
Depende de usted saber si el precio vale la pena.
EDITAR:
Funcionaría así:
feature_x
feature_y
yfeature_z
puede haber sido agregado también. Se convierte en una fusión "entre equipos". Por eso es un serio inconveniente.solo para que conste: creo que esto es en la mayoría de los casos una mala idea y debe hacerse con cautela porque el inconveniente de la fusión suele ser mayor que el que se obtiene a través de la gestión de dependencias / seguimiento de funciones adecuado.
fuente
:-/
Además, incluso aquellos que están (y que presionaron para pasar a git), no saben cómo hacer que nuestro proceso de desarrollo se ajuste a git. Suspiro. Serán unos meses difíciles, me temo, hasta que las cosas empiecen a ponerse más tranquilas. Gracias de todos modos, la suya es la respuesta más / única útil hasta ahora.La solución que está buscando es una herramienta de gestión de dependencias en coordinación con submódulos git
Herramientas como:
Puede usar esas herramientas para definir las dependencias de un proyecto.
Puede requerir que un submódulo sea al menos versión > 2.xx o denotar un rango de versiones que sean compatibles = 2.2. * O menos que una versión particular <2.2.3
Cada vez que lanza una nueva versión de uno de los paquetes, puede etiquetarlo con el número de versión, de esa manera puede incorporar esa versión específica del código en todos los demás proyectos
fuente
Submódulos
Debería intentar git submódulos , como se sugiere en un comentario.
Cuando el proyecto
P1
se refiere a los tres submódulosL1
,L2
yL3
, en realidad se almacena una referencia al compromete particulares en los tres repositorios: esos son los que trabajan versiones de cada uno de bibliotecas para ese proyecto .Por lo tanto, varios proyectos pueden funcionar con múltiples submódulos:
P1
puede referirse a la versión anterior de la bibliotecaL1
mientras el proyectoP2
usaba la nueva versión.¿Qué sucede cuando entrega una nueva versión de
L3
?L3
L2
trabajos conL3
, commit, ...L1
trabajos con nuevosL2
, ...P1
funcione con las nuevas versiones de todas las bibliotecas:P1
's copia de trabajo local delL1
,L2
yL3
, fetche los cambios que está interesado.git add L1 L2 L3
para confirmar la nueva referencia a los módulosP1
, prueba, revisión, solicitud de extracción, fusión ...Metodología
Sí, requiere revisiones independientes, porque cambia:
¿Estaría fuera del negocio porque entrega basura? (Tal vez no, en realidad). En caso afirmativo, debe realizar pruebas y revisar los cambios.
Con las herramientas git apropiadas (incluso
gitk
), puede ver fácilmente qué versiones de las bibliotecas usa cada proyecto, y puede actualizarlas de forma independiente de acuerdo con sus necesidades. Los submódulos son perfectos para su situación y no retrasarán su proceso.Tal vez pueda encontrar una manera de automatizar parte de este proceso, pero la mayoría de los pasos anteriores requieren cerebros humanos. La forma más efectiva de reducir el tiempo sería garantizar que sus bibliotecas y proyectos sean fáciles de evolucionar. Si su base de código puede manejar nuevos requisitos con gracia, las revisiones de código serán más simples y tomarán poco de su tiempo.
(Editar) otra cosa que podría ayudarlo es agrupar las revisiones de código relacionadas. Confirma todos los cambios y espera hasta que propague esos cambios a todas las bibliotecas y proyectos que los utilizan antes de sumbir las solicitudes de extracción (o antes de que se encargue de ellas). Terminas haciendo una revisión más grande para toda la cadena de dependencia. Tal vez esto pueda ayudarlo a ahorrar tiempo si cada cambio local es pequeño.
fuente
Entonces, lo que entiendo es que para P1 desea cambiar la interfaz L3 pero desea que los otros P2 y P3 que dependen de la interfaz L3 cambien de inmediato. Este es un caso típico de compatibilidad con versiones anteriores. Hay un buen artículo sobre esta preservación de la compatibilidad con versiones anteriores
Hay varias formas de resolver esto:
O
fuente
Si estoy resolviendo su problema correctamente:
Entonces, el objetivo es que puedes hacer P1 y L1 de una vez, y luego un mes después hacer L2 y L3 en otra.
En el mundo de Java, esto es trivial, y quizás la forma predeterminada de trabajar:
Por lo tanto, puede tener el código en su disco local para L3 que no se compilaría si se compilara contra la copia del P1 en el otro directorio de su disco; Afortunadamente no lo está haciendo. Java puede hacer esto directamente porque compilar / vincular cuentos contra archivos jar compilados, no sobre el código fuente.
No conozco una solución preexistente de uso generalizado para este problema para el mundo C / C ++, y me imagino que casi no quieres cambiar de idioma. Pero algo podría piratearse fácilmente con archivos de creación que hicieran lo mismo:
Incluso podría usar el soporte C / C ++ en maven , aunque la mayoría de los desarrolladores de C lo mirarían de manera extraña si lo hiciera ...
fuente
:)
Hay una solución simple: cortar ramas de lanzamiento en todo el repositorio, fusionar todas las correcciones a todos los lanzamientos enviados activamente (es fácil en caso claro debería ser posible en git).
Todas las alternativas crearán un desastre horrible con el tiempo y con el crecimiento del proyecto.
fuente