Diferencia entre Trunk y Branch en Control de Versiones

En el mundo del desarrollo de software, la gestión eficiente del código es fundamental para la colaboración y la entrega continua. Dos enfoques populares para organizar el trabajo en sistemas de control de versiones como Git son el Trunk-Based Development (TBD) y Git Flow. A medida que los sistemas de control de versiones se desarrollaron, surgieron varios estilos de desarrollo que permitieron a los programadores encontrar errores con más facilidad, crear código en paralelo con sus compañeros y acelerar el ritmo de publicación.

El Trunk-Based Development se ha convertido en una práctica habitual entre los equipos de DevOps y parte del ciclo de vida de DevOps, ya que simplifica las fases de fusión e integración. De hecho, el desarrollo basado en troncos es una práctica obligatoria de la CI y la CD. Permite a los desarrolladores crear ramas de corta duración con pequeñas confirmaciones, a diferencia de otras estrategias de ramas de funciones de larga duración. Como su nombre nos orienta, esta estrategia se basa en una sola rama denominada tronco, en los repositorios es llamada trunk o main, en adelante la llamaremos trunk. Esta rama será de larga duración ya que todos los procesos, ambientes, cambios, rollback entre otros estarán basados en dicha rama. Luego, la rama trunk es promovida donde se requiera, como por ejemplo en ambientes pre-productivos, producción, local, etc.

Por otro lado, Git Flow, que se popularizó primero, es un modelo de desarrollo más estricto en el que solo determinadas personas pueden aprobar los cambios en el código principal. Así se mantiene la calidad del código y se minimiza el número de errores. En Git Flow existen cinco tipos de ramas: main, develop, feature, release y hotfix. Es la rama principal de un repositorio, de hecho, es la que viene por omisión, integrada cuando se crea un repositorio. Esta rama es recomendable crearla al inicio de un proyecto, manteniéndose así, durante todo el proceso de desarrollo. La rama de lanzamiento debe utilizarse al preparar nuevas versiones de producción. La base de la rama revisión debe ser la rama main y debe fusionarse de nuevo en la rama main y develop. Git Flow tiene más ramas de mayor duración y confirmaciones más grandes que el desarrollo basado en troncos. Según este modelo, los desarrolladores crean una rama de función y retrasan su fusión con la rama principal del tronco hasta que la función esté completa. Git Flow también tiene líneas de rama principales independientes para el desarrollo, las correcciones, las funciones y las publicaciones. Existen diferentes estrategias para fusionar las confirmaciones entre estas ramas.

El desarrollo basado en troncos es un modelo más abierto, ya que todos los desarrolladores tienen acceso al código principal, lo que permite a los equipos iterar con rapidez y pone en práctica la CI y la CD. El desarrollo por tronco está mucho más simplificado, ya que se centra en la rama principal como fuente de correcciones y publicaciones. El desarrollo basado en troncos es una práctica obligatoria para la integración continua. El desarrollo basado en troncos disminuye la fricción de la integración del código.

Principios Fundamentales

Trunk-Based Development (TBD)

Trunk-Based Development (TBD) es una estrategia de control de versiones que promueve la colaboración continua y la integración frecuente de cambios en una única rama principal del código, conocida como "trunk" o "main". Este enfoque busca minimizar los conflictos de integración y acelerar el ciclo de entrega de software. Trunk-Based Development es una práctica de gestión de control de versiones en la que los desarrolladores integran pequeños y frecuentes cambios en una rama principal compartida, denominada "trunk" o "main". A diferencia de otros enfoques como Git Flow o Feature Branching, que fomentan el uso de múltiples ramas (por ejemplo, develop, release, hotfix, feature/*), Trunk-Based Development busca simplificar el flujo de trabajo y reducir los riesgos de integración tardía. Mientras Git Flow es útil en entornos con ciclos de lanzamiento largos y estructuras más formales, Trunk-Based Development está más alineado con metodologías ágiles y DevOps, donde la prioridad es la automatización, la productividad y la colaboración constante entre equipos.

El primer paso fundamental para adoptar Trunk-Based Development (TBD) es establecer una rama principal compartida como centro neurálgico del desarrollo. Esta práctica representa un cambio de paradigma frente a otros flujos de trabajo más tradicionales como Git Flow, donde las ramas de desarrollo (develop, feature/*, release/*, hotfix/*) son fundamentales. La convención moderna recomienda usar main como nombre de la rama principal en lugar de master, por razones de claridad y neutralidad. Establecer reglas claras para pequeñas ramas temporales (máx. 3. Aunque TBD impulsa la integración frecuente, eso no significa que se omita la calidad. Cambiar a TBD requiere compromiso del equipo.

En TBD no se tienen ramas alternas, ni bifurcaciones, ni cosas por el estilo, solo se trabaja con la rama trunk y cuando se tienen políticas de Pull Request se trabaja con el concepto de ramas features clonadas de trunk, siendo de carácter efímero y lo mas cortas posibles. Luego, la rama trunk es promovida donde se requiera, como por ejemplo en ambientes pre-productivos, producción, local, etc. Su versatilidad y respaldo la dan los tags o etiquetas, que hacen visible su momento en diferentes circunstancias del ciclo de vida del desarrollo de la aplicación en la que estemos trabajando.

El Trunk-Based Development permite a los desarrolladores crear ramas de corta duración con pequeñas confirmaciones. El alcance de las tareas para este tipo de desarrollo suele ser reducido para incrementar la frecuencia con la que los cambios se van incluyendo en la rama main. En algunos casos, incluso, los cambios se realizan directamente en main. En la perspectiva del desarrollador, no mucho cambia aparte de la utilización de convenciones de nombre para estas ramas cortas (ejemplo, tarea/ID-123, fix/ID-456). Lo único a tener en cuenta es que al tener una única rama estable, las funcionalidades que se vayan incluyendo deben mantenerse ocultas mediante mecanismos como banderas de funcionalidad (feature flags) hasta el momento de su despliegue formal.

Cada push al trunk debe ejecutar una batería de pruebas. Es difícil integrar cambios frecuentemente si el código está muy acoplado. Las banderas de características permiten integrar código en producción sin activarlo. No esperes a terminar todo para hacer push. Si usas ramas de funcionalidad, que duren solo unas horas o un día. Integrar frecuentemente es una práctica que debe estar respaldada por la cultura del equipo.

Un ejemplo de flujo con TBD:

  1. git checkout main
  2. git checkout -b tarea/ID-124
  3. echo "Cambio" >> readme.md
  4. git add readme.md
  5. git commit -m "Descripción del cambio"
  6. git push origin tarea/ID-124 # Se suben los cambios al repositorio
  7. # Para hacer merge desde otra máquina
  8. git checkout main
  9. git pull origin main
  10. git fetch -a # Hace fetch a todas las ramas, también puede usarse git fetch origin tarea/ID-124
  11. git merge tarea/ID-124
  12. git push origin main

En la actualidad, cuando pensamos en control de versiones para un proyecto de software, comúnmente pensamos en Git, una herramienta creada en 2005. A diferencia de otros sistemas de control de versiones, Git no tiene una preferencia por una estrategia tan definida. A nivel individual, esto no es problema, pero al encontrarnos en proyectos complejos una de las tareas iniciales debe ser definir el flujo de trabajo que se manejará para Git. Esto incluye definir formato para los nombres de ramas, cuando se crearán ramas, nombres de commits, estrategias para merge, y otros detalles que ayuden a mantener un historial de cambios limpio y ordenado.

El Trunk-Based Development se ha convertido en una práctica habitual entre los equipos de DevOps y parte del ciclo de vida de DevOps, ya que simplifica las fases de fusión e integración. De hecho, el desarrollo basado en troncos es una práctica obligatoria de la CI y la CD. Permite a los desarrolladores crear ramas de corta duración con pequeñas confirmaciones, a diferencia de otras estrategias de ramas de funciones de larga duración.

Google usa en sus repositorios TBD para el control de versiones y promueve su implementación. Cabe recordar que para trabajar con TBD se debe tener un equipo muy maduro técnicamente. Por ejemplo, para equipos que desarrollan pruebas automatizadas, la rama trunk será su rama productiva, en donde estarán todas las pruebas automatizadas estables y confiables. Pero aún así, no logramos hacer push de commits que no entren en conflicto. No hay dudas que la raíz del problema es la aplicación de la estrategia o el cómo seguimos el workflow.

En resumen, el Trunk-Based Development se basa en una única rama principal ("trunk" o "main") donde se integran continuamente pequeños cambios. Su objetivo es simplificar el flujo de trabajo, acelerar la integración y facilitar la CI/CD.

Diagrama comparativo de Trunk-Based Development vs. Git Flow

Git Flow

Git Flow es un flujo basado en ramas de funcionalidad, también conocidas como feature branches. En esta estrategia, no solo cambia como trabaja el desarrollador, sino también el proceso de despliegue de la aplicación. Los cambios se realizan a partir de una rama develop, en feature branches por tarea, siguiendo un formato para el nombre de la rama. En la rama de release, se incluyen los cambios que se tenían previamente en develop y se envían a main y develop para luego identificar la versión con una etiqueta. Para arreglos, se crean ramas de hotfix que son directamente enviadas a main y develop, de forma similar al caso de la rama release. Asegurando tener los arreglos de errores en la rama que utilizan los desarrolladores para basar sus cambios.

Git Flow tiene una estrategia bastante definida y reduce la cantidad de conflictos en comparación a TBD; todo esto a cambio de complejidad en los despliegues.

Ejemplo de flujo con Git Flow (saltando los pasos de push/pull):

  1. git checkout develop
  2. git checkout -b tarea/ID-123
  3. echo "ID-123" >> readme.md
  4. git commit -m "Tarea 123"
  5. git merge tarea/ID-123
  6. git checkout -b release-1 # Branch para release
  7. git checkout main # Preparación cuando todos los cambios estén en release
  8. git merge release-1
  9. git checkout -b hotfix/ID-456 # hotfix luego del release
  10. echo "ID-456" >> readme.md
  11. git add readme.md
  12. git commit -m "Hotfix 456"
  13. git checkout main
  14. git merge hotfix/ID-456 # Release directo del hotfix
  15. git checkout develop
  16. git merge main # Actualización de develop para incluir el hotfix

En Git Flow existen cinco tipos de ramas: main, develop, feature, release y hotfix. La rama de lanzamiento debe utilizarse al preparar nuevas versiones de producción. La base de la rama revisión debe ser la rama main y debe fusionarse de nuevo en la rama main y develop. Git Flow es una especie de idea abstracta de un flujo de trabajo de Git. Esto quiere decir que ordena qué tipo de ramas se deben configurar y cómo fusionarlas.

Git Flow tiene más ramas de mayor duración y confirmaciones más grandes que el desarrollo basado en troncos. Según este modelo, los desarrolladores crean una rama de función y retrasan su fusión con la rama principal del tronco hasta que la función esté completa. Git Flow también tiene líneas de rama principales independientes para el desarrollo, las correcciones, las funciones y las publicaciones.

Estructura de ramas en Git Flow

Comparación y Ventajas

Git Flow puede ser más adecuado para proyectos con ciclos de lanzamiento definidos y necesidades de mantenimiento específicas, mientras que TBD es ideal para equipos que buscan una entrega continua y rápida. Mientras GitFlow utiliza múltiples ramas de larga duración para gestionar el desarrollo, las correcciones y las versiones, TBD se centra en una única rama principal con integraciones frecuentes. Las revisiones de código se realizan de manera continua y rápida en TBD, lo que mejora la calidad del código y facilita la colaboración entre desarrolladores.

El desarrollo basado en troncos disminuye la fricción de la integración del código. Durante esta fase, pueden surgir conflictos si se han realizado modificaciones desde el inicio de la tarea nueva. En concreto, estos conflictos son cada vez más complejos a medida que los equipos de desarrollo crecen y la base de código se amplía. Esto ocurre cuando los desarrolladores crean ramas independientes que se desvían de la rama origen y otros desarrolladores están fusionando a la vez el código que se solapa.

En comparación, Git Flow puede reducir la cantidad de conflictos al tener ramas dedicadas para cada tipo de tarea, pero a costa de una mayor complejidad en el flujo de trabajo y despliegue.

La estructura TTB (Trunk, Tags, Branches) se ha convertido en el estándar de facto en los repositorios SVN. TTB son las iniciales de las tres carpetas que compondrán el primer nivel de directorios del repositorio: Trunk, Tags y Branches. Tags: Rama de gestión de versiones.

¿Cuándo usar cada estrategia?

Trunk-Based Development: para equipos pequeños, donde la complejidad del proyecto es baja y la estabilidad no es prioridad. Un ejemplo, serían herramientas de línea de comando o algunas librerías sencillas. También es puede verse en proyectos que están migrando de otros sistemas de control de versiones, pero que no reciben cambios frecuentes.

GitFlow: equipos maduros, con flujos de trabajo bien definidos. Esta estrategia se beneficia de mayor estabilidad en los despliegues, siendo elegido para proyectos complejos o con funcionalidades críticas.

GitHub Flow: más común en equipos chicos o medianos, donde la complejidad del proyecto puede variar. Es la opción favorita de muchos equipos ágiles por su simplicidad y ritmo rápido.

En resumen, la elección entre Trunk-Based Development y Git Flow depende de factores como el tamaño del equipo, la complejidad del proyecto, la necesidad de estabilidad y la velocidad de entrega deseada.

Trunk-Based Development: Simplificando Git 📍| Flujos de trabajo con Git 5/7

tags: #diferencia #entre #trunk #y #branch