¿Elegir entre proyectos individuales o múltiples en un repositorio git?

223

En un gitentorno en el que hemos modularizado la mayoría de los proyectos, nos enfrentamos a un proyecto por repositorio o a varios proyectos por problema de diseño de repositorio . Consideremos un proyecto modularizado:

myProject/
   +-- gui
   +-- core
   +-- api
   +-- implA
   +-- implB

Hoy tenemos un proyecto por repositorio . Da libertad a

  • release componentes individuales
  • tag componentes individuales

Pero también es engorroso para los branchcomponentes, ya que a menudo la ramificación apirequiere ramificaciones equivalentes corey quizás otros componentes.

Dado que queremos releasecomponentes individuales, ¿podemos obtener una flexibilidad similar al utilizar múltiples proyectos por diseño de repositorio ?

¿Qué experiencias hay y cómo / por qué abordó estos problemas?

Johan Sjöberg
fuente
1
Tengo un problema muy similar en este momento. Necesito publicar diferentes versiones de un proyecto, por lo que deberán estar en diferentes repositorios. Sin embargo, esta es una pesadilla para manejar. Sería genial si hubiera una manera de ramificar solo subdirectorios.
Andrew T Finnell
1
Cada módulo debe tener números de versión separados. Y lo usamos git-describe.
linquize
¡Me sorprende ver que Bit ( bitsrc.io ) y Lerna ( github.com/lerna/lerna ) no se mencionan! Puede obtener más información aquí: hackernoon.com/…
Yoni

Respuestas:

199

Hay tres desventajas principales en one project per repositoryla forma en que lo describió anteriormente. Estos son menos ciertos si son proyectos verdaderamente distintos, pero, según parece, los cambios a uno a menudo requieren cambios a otro, lo que realmente puede exagerar estos problemas:

  1. Es más difícil descubrir cuándo se introdujeron los errores. Las herramientas como se git bisectvuelven mucho más difíciles de usar cuando fractura su repositorio en sub-repositorios. Es posible, simplemente no es tan fácil, lo que significa que la caza de errores en tiempos de crisis es mucho más difícil.
  2. El seguimiento de todo el historial de una característica es mucho más difícil. Los comandos de recorrido de historial como git logsimplemente no generan un historial tan significativo con estructuras de repositorio fracturadas. Puede obtener resultados útiles con submódulos o subárboles, o mediante otros métodos programables, pero no es lo mismo que escribir tig --grep=<caseID>o git log --grep=<caseID>escanear todas las confirmaciones que le interesan. Su historia se vuelve más difícil de entender, lo que la hace menos útil cuando realmente la necesita.
  3. Los nuevos desarrolladores pasan más tiempo aprendiendo la estructura del Control de versiones antes de que puedan comenzar a codificar. Cada nuevo trabajo requiere procedimientos de recuperación, pero la fractura de un repositorio de proyectos significa que tienen que elegir la estructura de VC además de la arquitectura del código. En mi experiencia, esto es particularmente difícil para los desarrolladores nuevos que vienen de tiendas más tradicionales y centralizadas que usan un solo repositorio.

Al final, es un cálculo de costo de oportunidad. En un antiguo empleador, teníamos nuestra aplicación principal dividida en 35 sub-repositorios diferentes. Además de ellos, utilizamos un complicado conjunto de scripts para buscar en el historial, asegurarnos de que el estado (es decir, las ramas de producción frente a desarrollo) fuera el mismo en todos ellos, y desplegarlos individualmente o en masa.

Simplemente era demasiado; demasiado para nosotros al menos. La sobrecarga administrativa hizo que nuestras funciones fueran menos ágiles, las implementaciones fueron mucho más difíciles, la enseñanza de nuevos desarrolladores tomó demasiado tiempo y, al final, apenas podíamos recordar por qué fracturamos el repositorio en primer lugar. Un hermoso día de primavera, gasté $ 10 por una tarde de tiempo de cómputo en clúster en EC2. Volví a juntar los repositorios con un par de docenas de git filter-branchllamadas. Nunca miramos hacia atrás.

Christopher
fuente
77
Como tema aparte, hay pocas cosas más divertidas como administrador de repositorios que comprar tiempo en un sistema que puede hacer en dos horas lo que su computadora portátil no podría hacer en 20, por menos del precio del almuerzo. A veces realmente amo internet.
Christopher
2
¿Cómo lanzaría esos proyectos individuales como lanzamientos separados? ¿O nunca necesitas hacer eso? Ese es el problema que tengo. Con si necesita crear una V1 del Proyecto A y una V2 del Proyecto B.
Andrew T Finnell
55
Para moverse entre "un proyecto por repositorio" y "repositorios múltiples", considere git-subtree (buena explicación en stackoverflow.com/a/17864475/15585 )
determine el
1
Escribí un script para automatizar esto para casos de uso común: github.com/Oakleon/git-join-repos
chrishiestand
¿Qué es una "estructura de VC"?
Robert Harvey
60

Christopher hizo un muy buen trabajo al enumerar las desventajas de un modelo de un proyecto por repositorio. Me gustaría discutir algunas de las razones por las que podría considerar un enfoque de repositorio múltiple. En muchos entornos en los que he trabajado, un enfoque de múltiples repositorios ha sido una solución razonable, pero la decisión de cuántos repositorios tener y dónde hacer los recortes no siempre ha sido fácil.

En mi posición actual, migré un gigantesco repositorio CVS de repositorio único con más de diez años de historia a varios repositorios git. Desde esa decisión inicial, el número de repositorios ha crecido (a través de las acciones de otros equipos), hasta el punto de sospechar que tenemos más de lo que sería óptimo. Algunos nuevos empleados han sugerido fusionar los repositorios, pero he argumentado en contra. El proyecto Wayland tiene una experiencia similar. En una charla que vi recientemente, tenían, en un momento, más de 200 repositorios de git, por lo cual el líder se disculpó. Mirando su sitio web , veo que ahora están en 5, lo que parece razonable. Es importante observar que unir y dividir repositorios es una tarea manejable, y está bien experimentar (dentro de lo razonable).

Entonces, ¿cuándo podrías querer múltiples repositorios?

  1. Un repositorio único sería demasiado grande para ser eficiente.
  2. Sus repositorios están débilmente acoplados o desacoplados.
  3. Un desarrollador generalmente solo necesita uno, o un pequeño subconjunto de sus repositorios para desarrollar.
  4. Por lo general, desea desarrollar los repositorios de forma independiente, y solo necesita sincronizarlos ocasionalmente.
  5. Desea fomentar más modularidad.
  6. Diferentes equipos trabajan en diferentes repositorios.

Los puntos 2 y 3 solo son significativos si el punto 1 se cumple. Al dividir nuestros repositorios, disminuí significativamente las demoras sufridas por nuestros colegas externos, reduje el consumo de disco y mejoré el tráfico de red.

4 y 5 son más sutiles. Cuando divide los repositorios de digamos un cliente y un servidor, esto hace que sea más costoso coordinar los cambios entre el código del cliente y el servidor. Esto puede ser positivo, ya que fomenta una interfaz desacoplada entre los dos.

Incluso con las desventajas de los proyectos de múltiples repositorios, se hace mucho trabajo respetable de esa manera: wayland y boost vienen a la mente. No creo que haya llegado a un consenso con respecto a las mejores prácticas, y se requiere cierto juicio. Las herramientas para trabajar con múltiples repositorios (git-subtree, git-submodule y otros) aún se están desarrollando y experimentando. Mi consejo es experimentar y ser pragmático.

Spacemoose
fuente
77
Esta respuesta sería aún más útil con una referencia para respaldar la afirmación: "unir y dividir repositorios es una tarea manejable".
Comodín el
3
Los repositorios múltiples también pueden funcionar contra la modularidad porque hacen que sea más difícil cambiar el código compartido. Las dependencias de repo cruzado dificultan la integración, pueden romper el código más fácilmente (incluso si tiene buenas herramientas para verificar esto) y la amenaza de romper el código fuera del repo desalienta las interfaces de refactorización, que es una de sus herramientas más poderosas para hacer cosas Más modular.
Curt J. Sampson
Todo lo relacionado con MicroServices y diseño DDD es válido aquí. Debes minimizar el código compartido.
Arwin
49

A medida que utilizamos GitHub, en realidad tenemos varios proyectos en un repositorio, pero nos aseguramos de que esos proyectos / módulos estén debidamente modularizados (utilizamos convenciones -api y -core + Maven + comprobación estática y de tiempo de ejecución e incluso podríamos ir a OSGi algún día para arrancar) .

¿En qué ahorra? Bueno, no tenemos que emitir múltiples solicitudes de extracción si estamos cambiando algo pequeño en varios proyectos. Los problemas y Wiki se mantienen centralizados, etc.

Todavía tratamos cada módulo / proyecto como un proyecto independiente adecuado y lo compilamos e integramos por separado en nuestro servidor de CI, etc.

Martijn Verburg
fuente
1
Muy interesante. Sospecho que este es un modelo común en github. Si enfrenta lanzamientos de componentes individuales, ¿emplea algo como, submoduleso lanza / etiqueta todo el repositorio?
Johan Sjöberg
submódulos si tenemos que hacerlo, pero por ahora tenemos la versión del padre hacia abajo.
Martijn Verburg
En mi empleador actual, utilizamos una estrategia similar y empaquetamos metadatos sobre el compromiso más reciente en un proyecto en los diversos archivos de manifiesto de artefactos (es decir, los resultados de git log -1 -- <project_dir>). Realmente es genial. Esta respuesta merece más votos a favor.
Christopher
22

Para mí, la principal diferencia en el uso de uno o más de un repositorio son las respuestas a las siguientes preguntas:

  • ¿Las múltiples partes desarrolladas por el mismo equipo, tienen el mismo ciclo de lanzamiento, el mismo cliente? Entonces hay menos razones para dividir el único repositorio.
  • ¿Las partes múltiples dependen mucho unas de otras? Por lo tanto, dividir el modelo, el controlador y la interfaz de usuario (incluso cuando son partes diferentes) no es muy sensible, debido a la alta dependencia entre ellos. Pero si 2 partes solo tienen una pequeña dependencia, que se implementa mediante una interfaz estable que solo se cambia cada pocos años, sería prudente dividir las 2 partes en 2 repositorios.

Solo como ejemplo, tengo una pequeña aplicación (solo cliente) que verifica la "calidad" de un repositorio de Subversion. Existe la implementación principal, que podría iniciarse desde la línea de comandos, y funciona bien con Java 6. Pero he comenzado a implementar una interfaz de usuario, que usa JavaFX como parte de Java 8. Así que he dividido el 2 y he creado un segundo repositorio (con un segundo proceso de compilación), con diferente programación, ...

Me gustan las respuestas anteriores (las voté), pero creo que no son toda la historia real. Así que también quería agregar los argumentos para dividir los repositorios. Entonces, la respuesta real (cuándo dividirse) puede estar en algún lugar en el medio ...

mliebelt
fuente
0

A partir de su ejemplo, los repositorios deben configurarse en términos de cuán interdependientes son. Aquí se aplica todo el razonamiento sobre el diseño de MicroServices y el diseño impulsado por dominio: en algunos casos, el código duplicado es aceptable, funciona con interfaces, no interrumpe la compatibilidad a menos que realmente sea necesario, etc.

Ahora, en mi opinión, una interfaz de usuario debe ser independiente del backend. Por lo tanto, un repositorio de proyectos de IU generalmente debe contener el código de IU y el controlador de cliente. El controlador del cliente se conectará con los controladores de servicio de manera abstracta. Utilizarán un cliente de servicio / abstracción de API que se versiona por separado del servicio, de modo que un servicio se pueda actualizar sin romper el cliente (puede haber varios clientes diferentes).

Por lo tanto, un servicio en sí debería ser su propio repositorio. En mi opinión, el servicio es solo una envoltura de alguna lógica empresarial de punto único de verdad. Por lo tanto, la lógica de negocios generalmente debe estar separada de la tecnología de servicio que la aloja. Por otro lado, la implementación del repositorio suele estar tan estrechamente conectada a la lógica de negocios, que podría integrarse en el mismo repositorio. Pero incluso allí su kilometraje puede variar.

Por supuesto, los proyectos simples que es poco probable que cambien mucho en términos de tecnología o que admitan múltiples pilas, donde toda la interfaz de usuario se puede alojar desde la misma fuente que el back-end y los servicios de back-end generalmente solo son utilizados por ese mismo cliente, pueden beneficiarse de más repositorios muy integrados.

En ese caso, probablemente estaría bien con solo tener la vertical completa en un repositorio, y concentrarse en asegurarse de que sus dominios funcionales estén correctamente independientes en su propio repositorio. Entonces todavía tiene la mayoría de las ventajas de los repositorios más pequeños y, de lo contrario, poca sobrecarga.

Arwin
fuente