Close

Git y dependencias de proyectos

Primer plano de Nicola Paolucci
Nicola Paolucci

Experto en desarrollo

Analiza estas preguntas. ¿Cómo gestionas las dependencias de proyectos con Git? Nuestro proyecto se compone de varios repositorios interdependientes. Actualmente los gestionamos con svn:externals. ¿Cuál es la mejor manera de gestionarlos con Git? ¿Cómo se divide un repositorio muy grande en componentes más pequeños usando Git? Estos son algunos ejemplos de las preguntas más frecuentes que recibimos en la etapa europea de nuestra reciente gira Getting Git Right (Usa Git correctamente).

Este tema parece ser uno de los grandes problemas de muchos equipos de software que adoptan Git, así que en este artículo intentaré aclararlo un poco.

Obviamente, las dependencias de proyectos y la infraestructura de compilación son dos áreas interrelacionadas, e incluso en Atlassian se ha generado un debate interno sobre el "futuro de las compilaciones".

Tener distintos repositorios en lugar de uno solo puede complicar algunas cosas. No obstante, es un paso relativamente natural (a veces obligatorio) en la evolución de un proyecto de software por, al menos, dos razones principales: el aumento de los tiempos de compilación y las dependencias compartidas entre proyectos.

Analiza estas preguntas. ¿Cómo gestionas las dependencias de proyectos con Git? Nuestro proyecto se compone de varios repositorios interdependientes. Actualmente los gestionamos con svn:externals. ¿Cuál es la mejor manera de gestionarlos con Git? ¿Cómo se divide un repositorio muy grande en componentes más pequeños usando Git? Estos son algunos ejemplos de las preguntas más frecuentes que recibimos en la etapa europea de nuestra reciente gira Getting Git Right (Usa Git correctamente).

Este tema parece ser uno de los grandes problemas de muchos equipos de software que adoptan Git, así que en este artículo intentaré aclararlo un poco.

Obviamente, las dependencias de proyectos y la infraestructura de compilación son dos áreas interrelacionadas, e incluso en Atlassian se ha generado un debate interno sobre el "futuro de las compilaciones".

Tener distintos repositorios en lugar de uno solo puede complicar algunas cosas. No obstante, es un paso relativamente natural (a veces obligatorio) en la evolución de un proyecto de software por, al menos, dos razones principales: el aumento de los tiempos de compilación y las dependencias compartidas entre proyectos.


Visión general: directrices y soluciones que dejan mucho que desear


Volvamos a la pregunta inicial: ¿Cómo supervisas y gestionas las dependencias de proyectos con Git?

Si es posible, ¡no lo haces!

Bromas aparte, voy a responder primero de forma general y luego profundizaré más en la cuestión. Ten en cuenta que no hay una fórmula mágica, ni en Git ni en otras soluciones, que resuelva fácilmente todos los problemas relacionados con las dependencias de proyectos.

Una vez que un proyecto supera cierto tamaño, es una buena idea dividirlo en componentes lógicos, pero no esperes a tener más de 100 millones de líneas de código en un único repositorio para hacerlo. Las directrices siguientes son solo pautas para que puedas diseñar tu propia estrategia.

Logotipo de Git
Material relacionado

Instalar Git

Logotipo de Bitbucket
VER LA SOLUCIÓN

Aprende a usar Git con Bitbucket Cloud

Primera opción: usar una herramienta de compilación o dependencias apropiada en lugar de Git


Una herramienta de gestión de dependencias es el método que recomiendo actualmente para gestionar los problemas de crecimiento y los tiempos de compilación de los proyectos de gran tamaño.

Mantén cada módulo en un repositorio distinto y gestiona su interdependencia con una herramienta diseñada para ello. Hay una para (casi) cada pila tecnológica existente. Algunos ejemplos:

  • Maven (o Gradle) si usas Java
  • Npm para aplicaciones de nodo
  • Bower, Component.io, etc. si usas JavaScript (actualizado)
  • Pip y requirements.txt si usas Python
  • RubyGems y Bundler si usas Ruby
  • NuGet para .NET
  • Ivy (o alguna acción CMake personalizada) para C++ (actualizado)
  • Aplicaciones iOS de CocoaPods para Cocoa
  • Composer o Phong para PHP (añadido)
  • En Go, la infraestructura de compilación o dependencia está bastante integrada en el lenguaje (aunque se ha estado trabajando en una solución más completa; consulta godep). Para nuestro servidor Git, Bitbucket Server, usamos tanto Maven como Bower. En el momento de la compilación, la herramienta elegida extraerá las versiones correctas de las dependencias para que se pueda compilar tu proyecto principal. Algunas de estas herramientas tienen limitaciones y hacen suposiciones que no son óptimas, pero están probadas y son viables.

Problemas de dividir tu proyecto

Al comienzo de un proyecto, todo se empaqueta de manera simplista en una compilación. No obstante, a medida que el proyecto crece, esto puede hacer que la compilación sea demasiado lenta, por lo que deberás almacenarla "en caché" y aquí es donde entra en acción la gestión de dependencias. Esto, por cierto, significa que los submódulos (consúltalos más abajo) se prestan muy bien a los lenguajes dinámicos, por ejemplo. Básicamente, creo que los tiempos de compilación son algo a lo que todos debemos prestar atención en algún momento. Por eso, deberías usar una herramienta de gestión de dependencias.

Dividir los componentes en distintos repositorios conlleva serios problemas. Aquí los expongo en un orden cualquiera:

  • Para realizar un cambio en un componente se requiere una versión.
  • Lleva tiempo y puede fallar por muchas razones estúpidas.
  • Parece inútil para realizar pequeños cambios.
  • Requiere la configuración manual de nuevas compilaciones para cada componente.
  • Dificulta la detección de los repositorios.
  • Se debe usar la refactorización cuando no todas las fuentes están disponibles en un único repositorio.
  • En algunas configuraciones (como la nuestra), la actualización de las API requiere una versión de hito del producto, luego del complemento y de nuevo del producto. Probablemente nos hayamos dejado algunas cosas, pero seguro que entiendes la idea general. Estamos lejos de tener una solución perfecta para resolver el problema.

Segunda opción: usar un submódulo de Git


Si no puedes o no quieres usar una herramienta de dependencias, Git te permite gestionar submódulos. Los submódulos pueden ser prácticos, sobre todo para los lenguajes dinámicos. Sin embargo, no siempre lograrán evitar que la compilación sea lenta. Ya he escrito directrices y consejos al respecto y también he buscado alternativas. En Internet en general también hay argumentos en contra de ellos.

Coincidencia 1:1 entre svn:external y Git

Pero, si buscas una coincidencia uno a uno entre svn:externals y Git, debes usar submódulos y asegurarte de que estos submódulos solo hagan un seguimiento de las ramas de versiones y no de confirmaciones aleatorias.

Tercera opción: usar otras herramientas de compilación y dependencia de pila cruzada


No siempre tendrás un proyecto completamente uniforme y que se pueda compilar y ensamblar con una sola herramienta. Por ejemplo, algunos proyectos móviles necesitarán hacer malabarismos con las dependencias de Java y C++, o usar herramientas patentadas para generar activos. Para esas situaciones más complejas, puedes mejorar Git con una capa adicional en la parte superior. Un claro ejemplo de ello es el repositorio de Android.

Otras herramientas de compilación que merece la pena considerar:

Conclusiones y lecturas adicionales


Charles O'Farrell sugirió muy acertadamente lecturas adicionales relacionadas con la infraestructura de compilación (y Maven), un tema muy interesante para la reflexión:

Me gustaría terminar con esta excelente cita del último de los artículos que acabo de mencionar. Aunque hace referencia a Maven, también se podría aplicar a otras herramientas de compilación y dependencias:

"Lo único que hace una caché es acelerar las cosas. Aunque eliminaras una caché por completo, el sistema circundante funcionaría igual, solo que más despacio. Una caché tampoco tiene efectos secundarios. Independientemente de lo que hayas hecho con una caché en el pasado, una consulta concreta a la caché devolverá el mismo valor a la misma consulta en el futuro.

La experiencia de Maven es muy diferente de lo que estoy explicando. Los repositorios de Maven se usan como cachés, pero sin tener las propiedades de las cachés. Cuando pides algo a un repositorio de Maven, lo que has hecho en el pasado es muy importante. La consulta devuelve lo más reciente que has introducido. Incluso puede fallar, si pides algo antes de introducirlo".

Nicola Paolucci

Nicola is an all-round hacker who loves exploring and teaching bleeding edge technologies. He writes and talks about Git, development workflows, code collaboration and more recently about Docker. Prior to his current role as Developer Instigator at Atlassian he led software teams, built crowd sourcing applications for geo-spacial data, worked on huge e-commerce deployments. Little known facts about Nicola: he gesticulates a lot while speaking (being Italian), lives in Amsterdam and rides a Ducati.


Compartir este artículo

Lecturas recomendadas

Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.

Gente que colabora utilizando un muro lleno de herramientas

Blog de Bitbucket

Ilustración de Devops

Ruta de aprendizaje de DevOps

Demostraciones de funciones con expertos de Atlassian del Centro de demostraciones

Cómo funciona Bitbucket Cloud con Atlassian Open DevOps

Suscríbete para recibir el boletín de DevOps

Thank you for signing up