¿Qué es Trunk-Based Development?

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. A continuación, se presenta un resumen detallado de los principios, beneficios y consideraciones clave de TBD.
¿Qué es Trunk-Based Development?
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". Este modelo evita la creación de ramas de desarrollo de larga duración, promoviendo en su lugar la integración continua y la entrega rápida de software.
A diferencia de otros enfoques como Git Flow o Feature Branching (en la imagen), 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.
Al eliminar la complejidad innecesaria del manejo de ramas prolongadas, esta estrategia facilita el testing automatizado, el deployment continuo y una mayor calidad en el software entregado.
Principios fundamentales de TBD
Los iremos desarrollando a lo largo de este artículo. De momento te los enumero:
Integración continua: Los desarrolladores integran sus cambios en la rama principal varias veces al día, lo que facilita la detección temprana de errores y reduce los conflictos de integración.
Ramas de corta duración: Si se utilizan ramas, estas son de vida corta, generalmente de horas o pocos días, y se integran rápidamente al trunk.
Revisión de código continua: Las revisiones de código se realizan de manera continua y rápida, lo que mejora la calidad del código y facilita la colaboración entre desarrolladores.
Automatización de pruebas: Se implementan pruebas automatizadas que se ejecutan con cada integración para garantizar la estabilidad y calidad del código.
Uso de feature flags: Se emplean banderas de características para activar o desactivar funcionalidades en producción sin necesidad de desplegar nuevo código, permitiendo una mayor flexibilidad y control.
Beneficios de Trunk-Based Development
Reducción de conflictos de integración: Al integrar cambios frecuentemente, se minimizan los conflictos que suelen surgir al fusionar ramas de larga duración.
Entrega continua: El código en la rama principal está siempre en un estado desplegable, lo que permite realizar entregas frecuentes y rápidas.
Mejora en la calidad del código: Las revisiones continuas y las pruebas automatizadas contribuyen a mantener un código de alta calidad.
Mayor colaboración: Al trabajar en una única rama compartida, se fomenta la colaboración y comunicación constante entre los miembros del equipo.
Comparación con GitFlow
Mientras que 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. GitFlow 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.
Paso 1: Establecer una Rama Principal Compartida
Introducción
El primer paso fundamental para adoptar Trunk-Based Development (TBD) es establecer una rama principal compartida como centro neurálgico del desarrollo. Esta rama es comúnmente denominada main
o trunk
, y todos los desarrolladores integran directamente (o a través de ramas muy breves) su trabajo en ella.
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. En TBD, simplificamos la topología del repositorio para maximizar la velocidad de integración y minimizar la divergencia.
¿Por qué una sola rama?
Mantener una única rama principal compartida tiene los siguientes beneficios:
- Evita la deriva de código entre ramas largas.
- Promueve la integración continua, ya que todos los cambios convergen rápidamente.
- Minimiza el coste de la fusión, al hacer merges pequeños y frecuentes.
- Aumenta la visibilidad del estado actual del producto, porque lo que hay en
main
es lo que hay.
Pasos para establecerla correctamente
1. Nombrar la rama principal
La convención moderna recomienda usar main
como nombre de la rama principal en lugar de master
, por razones de claridad y neutralidad. En proyectos más antiguos, puedes renombrar así:
2. Bloquear el uso de ramas largas
Configura el entorno de desarrollo y los repositorios (por ejemplo, en GitHub, GitLab o Bitbucket) para:
- Restringir la creación de ramas de larga duración.
- Desalentar el uso de ramas
develop
,release
, etc. - Establecer reglas claras para pequeñas ramas temporales (máx. 1–2 días).
3. Activar protección y revisión en main
Aunque TBD impulsa la integración frecuente, eso no significa que se omita la calidad. Puedes:
- Activar branch protection rules que exijan que los commits a
main
pasen por PR (pull request). - Requerir revisiones ligeras o rotativas.
- Automatizar pruebas para impedir integraciones defectuosas.
En GitHub, por ejemplo:
Settings > Branches > Branch Protection Rules > Require status checks to pass before merging
4. Automatizar la integración y las pruebas
Cada cambio en main
debe:
- Ser testeado automáticamente mediante CI (por ejemplo, GitHub Actions, GitLab CI/CD, CircleCI).
- Lanzar procesos de despliegue automáticos si corresponde (CD).
Este pipeline debe ser rápido (<10 minutos idealmente), confiable y visible para todos.
5. Educar al equipo
Cambiar a TBD requiere compromiso del equipo. Algunas acciones útiles:
- Realizar formaciones o talleres sobre flujo de trabajo con una rama compartida.
- Establecer normas: "nunca rompas
main
", "integra al menos una vez al día", "usa feature toggles", etc. - Incentivar la colaboración en cambios grandes para evitar bloqueos.
Buenas prácticas adicionales
- Commits pequeños y atómicos: Evita grandes commits que dificulten las revisiones y el troubleshooting.
- Mensajes de commit claros: Usa convenciones como Conventional Commits (
feat:
,fix:
,refactor:
…). - Feature toggles: Activa/desactiva funcionalidades en producción sin necesidad de ramas largas.
Veamos un ejemplo de como activar una nueva funcionalidad con feature toggle en Python
Supongamos que estás desarrollando una API y quieres introducir una nueva funcionalidad de búsqueda avanzada, pero sin romper la versión actual en producción. En lugar de crear una rama larga, usas un toggle para activarla o no:
Ahora hacemos commit, dejando un mensaje claro:
feat:
indica que estás añadiendo una nueva funcionalidad al código (útil para changelogs automatizados).- El resto del mensaje describe claramente qué se está incorporando: el feature toggle para activar o desactivar la búsqueda avanzada.
Otros ejemplos comunes de mensaje en el commit incluirían:
fix: corrige error al desactivar la búsqueda avanzada
refactor: reorganiza lógica de búsqueda sin cambiar funcionalidad
test: añade pruebas unitarias para toggle de búsqueda avanzada
Posibles dificultades
- Rupturas accidentales: Si alguien introduce código defectuoso en
main
, todos se ven afectados. Por eso CI y revisión son imprescindibles. - Resistencia al cambio: Equipos acostumbrados a Git Flow pueden tener miedo de "romper cosas". Aquí es clave la formación.
- Cambios grandes: Para grandes refactors o features complejas, usar feature branches de muy corta duración o técnicas como branch by abstraction.
Ejemplo realista
Supón que trabajas con un equipo de 4 desarrolladores. Todos comparten la rama main
y se organizan así:
- Cada uno crea una rama
feat/nueva-funcionalidad
y hace push el mismo día. - Cada PR se revisa rápidamente (máximo 30 minutos desde que se abre).
- Al hacer merge, los tests corren automáticamente.
- Si todo va bien, se despliega en staging automáticamente.
En este contexto, no hay ramas develop
, ni release
, ni semanas de trabajo sin integración.
Paso 2: Fomentar Integraciones Frecuentes
Uno de los principios esenciales del Trunk-Based Development (TBD) es que los desarrolladores deben integrar sus cambios en la rama principal varias veces al día. Esta práctica, conocida como frequent commits o continuous integration, es vital para mantener un código limpio, coherente y en constante evolución.
Integrar con frecuencia no es solo un hábito técnico, sino una filosofía que prioriza la comunicación continua entre personas, la visibilidad colectiva del código y la responsabilidad compartida del producto.
¿Qué significa integrar con frecuencia?
En el contexto de TBD, "integrar frecuentemente" implica:
- Que cada desarrollador sincroniza su trabajo con el trunk al menos una o dos veces por jornada de trabajo.
- Que las integraciones son pequeñas y manejables, no grandes paquetes de cambios acumulados.
- Que el trunk se mantiene siempre en un estado estable, desplegable y verificable mediante pruebas automáticas.
Beneficios de integrar frecuentemente
1. Reducción de conflictos
Integrar frecuentemente reduce drásticamente los conflictos de fusión (merge conflicts), ya que:
- El código divergente se detecta rápidamente.
- Las diferencias entre desarrolladores se resuelven en horas, no en semanas.
- Se evita la "sorpresa" de cambios incompatibles acumulados.
2. Visibilidad y colaboración
Cuando todos integran con regularidad:
- Todo el equipo ve lo que los demás están haciendo en tiempo real.
- Se fomentan conversaciones técnicas tempranas y constructivas.
- El conocimiento del sistema se distribuye de forma natural.
3. Mejora continua
Las integraciones frecuentes habilitan:
- La mejora constante del producto.
- El feedback inmediato tras cada cambio (gracias a CI/CD).
- La corrección rápida de errores y la iteración ágil.
Requisitos para que funcione
Para que la integración frecuente sea efectiva, deben darse ciertas condiciones técnicas y culturales.
1. Tests automáticos rápidos y fiables
Cada push al trunk debe ejecutar una batería de pruebas. Cuanto más rápido y fiable sea este feedback, más seguro será integrar a menudo.
- Unit tests en segundos.
- Integration tests en minutos.
- Fail fast: que fallen rápido y con mensajes útiles.
2. Integración continua (CI) bien configurada
Herramientas como GitHub Actions, GitLab CI, Jenkins o CircleCI deben estar integradas al repositorio para:
- Ejecutar automáticamente los tests tras cada push o PR.
- Notificar a los desarrolladores del resultado.
- Bloquear merges si los tests fallan.
3. Desacoplamiento y modularidad
Es difícil integrar cambios frecuentemente si el código está muy acoplado. Algunos principios útiles:
- Single Responsibility Principle.
- Micro-commits: cada cambio realiza una tarea clara.
- Uso de interfaces o abstracciones para facilitar refactors incrementales.
4. Pequeños pasos (baby steps)
Romper funcionalidades grandes en pequeños pasos ayuda a:
- Integrar más rápido.
- Probar partes aisladas.
- Usar feature toggles para funcionalidades incompletas.
5. Uso de Feature Flags
Las banderas de características permiten integrar código en producción sin activarlo. Esto:
- Elimina la necesidad de mantener ramas largas.
- Permite pruebas A/B y despliegues progresivos.
- Facilita revertir sin hacer rollback de código.
Técnicas para lograrlo
✅ Commit temprano, commit a menudo
Realiza pequeños commits funcionales y súbelos tan pronto como sea posible.
✅ Push en medio del trabajo
No esperes a terminar todo para hacer push. Es preferible subir parte del trabajo, protegido por un feature flag
, a quedarte con días de trabajo fuera del trunk.
✅ Pull frecuente del trunk
Antes de comenzar el día o cada pocas horas:
Mantener tu entorno sincronizado evita sorpresas desagradables al hacer merge.
✅ Short-lived branches
Si usas ramas de funcionalidad, que duren solo unas horas o un día. Ejemplo:
Qué evitar
- ❌ Ramas que duran varios días.
- ❌ Esperar a "tenerlo todo listo" para integrar.
- ❌ Introducir cambios grandes sin tests.
- ❌ Integrar sin revisar el estado del trunk (pull).
- ❌ Depender solo de integración manual (sin CI/CD).
Cultura de equipo: un factor clave
Integrar frecuentemente es una práctica que debe estar respaldada por la cultura del equipo. Esto incluye:
- Confianza entre desarrolladores.
- Valentía para subir código incompleto (pero protegido).
- Disciplina para escribir tests desde el principio.
- Revisión rápida y constante de PRs.
- Tolerancia al cambio constante, entendiendo que el código está vivo.
Ejemplo práctico
En un equipo que sigue TBD correctamente:
- Pedro comienza su día, hace
git pull origin main
. - Crea una rama
feat/nueva-alerta
, y en 2 horas termina la primera parte. - Abre una PR con tests y la etiqueta
#WIP
(Work In Progress). - Su compañero Jaime la revisa al momento y sugiere un cambio.
- Pedro lo aplica, se pasa CI, y Jaime mergea a
main
. - Al final del día, Pedro ha integrado 3 veces a
main
.