6. Ramas Avanzadas y Git Flow
En este documento se explican las estrategias avanzadas de ramificación, incluyendo Git Flow, GitHub Flow y otras metodologías para gestionar el desarrollo de software de manera eficiente y organizada.
1. Conceptos Fundamentales de Ramificación
1.1. ¿Por qué usar Ramas?
Las ramas permiten:
- Desarrollar funcionalidades en paralelo sin interferir con el código principal
- Mantener un historial limpio y organizado
- Facilitar la colaboración entre equipos
- Aislar experimentos y pruebas
- Implementar procesos de despliegue controlados
1.2. Tipos de Ramas Comunes
- main/master: Rama principal con código estable y desplegable
- develop: Rama de desarrollo donde se integran nuevas funcionalidades
- feature: Ramas para desarrollar funcionalidades específicas
- release: Ramas para preparar nuevas versiones
- hotfix: Ramas para correcciones urgentes en producción
2. Git Flow
2.1. ¿Qué es Git Flow?
Git Flow es una metodología de ramificación creada por Vincent Driessen que define un modelo estricto de ramificación diseñado alrededor del lanzamiento del proyecto.
2.2. Estructura de Ramas en Git Flow
graph TB
A[main] --> B[hotfix]
A --> C[release]
D[develop] --> C
D --> E[feature]
B --> A
B --> D
C --> A
C --> D
E --> D
2.3. Instalación de Git Flow
# Ubuntu/Debian
sudo apt-get install git-flow
# macOS
brew install git-flow-avh
# Windows (Git Bash)
curl -L -O https://raw.github.com/nvie/gitflow/develop/contrib/gitflow-installer.sh
bash gitflow-installer.sh
2.4. Inicialización de Git Flow
git flow init
Esto configurará automáticamente las ramas principales y las convenciones de nomenclatura.
3. Trabajando con Git Flow
3.1. Ramas Feature
Crear una nueva funcionalidad:
git flow feature start nueva-funcionalidad
Trabajar en la funcionalidad:
# Realizar commits normalmente
git add .
git commit -m "feat: implementar nueva funcionalidad"
Finalizar la funcionalidad:
git flow feature finish nueva-funcionalidad
Publicar funcionalidad para colaboración:
git flow feature publish nueva-funcionalidad
3.2. Ramas Release
Crear una nueva versión:
git flow release start 1.2.0
Finalizar la versión:
git flow release finish 1.2.0
Esto:
- Fusiona la rama release en main
- Crea un tag con la versión
- Fusiona los cambios de vuelta a develop
- Elimina la rama release
3.3. Ramas Hotfix
Crear un hotfix:
git flow hotfix start 1.2.1
Finalizar el hotfix:
git flow hotfix finish 1.2.1
4. GitHub Flow (Alternativa Simplificada)
4.1. Principios de GitHub Flow
GitHub Flow es más simple que Git Flow y se basa en:
- Solo existe una rama principal (main)
- Cualquier cambio se hace en ramas feature
- Las ramas feature se fusionan mediante Pull Requests
- Lo que está en main es desplegable
4.2. Flujo de Trabajo GitHub Flow
# 1. Crear rama feature
git checkout -b mi-nueva-funcionalidad
# 2. Desarrollar y hacer commits
git add .
git commit -m "feat: añadir nueva funcionalidad"
# 3. Subir rama
git push -u origin mi-nueva-funcionalidad
# 4. Crear Pull Request en GitHub
# 5. Revisar y aprobar
# 6. Fusionar a main
# 7. Eliminar rama feature
5. Estrategias Avanzadas de Merge
5.1. Tipos de Merge
# Merge normal (crea commit de merge)
git merge feature-branch
# Fast-forward merge (no crea commit de merge)
git merge --ff-only feature-branch
# Squash merge (combina todos los commits en uno)
git merge --squash feature-branch
5.2. Rebase vs Merge
Rebase - Historial lineal:
git checkout feature-branch
git rebase main
Merge - Preserva historial:
git checkout main
git merge feature-branch
5.3. Rebase Interactivo
git rebase -i HEAD~3 # Modifica los últimos 3 commits
Opciones disponibles:
pick: Usar commit tal como estáreword: Cambiar mensaje del commitedit: Pausar para editar el commitsquash: Combinar con commit anteriordrop: Eliminar commit
6. Gestión de Conflictos Avanzada
6.1. Herramientas para Resolver Conflictos
# Configurar herramienta de merge
git config --global merge.tool vimdiff
# Usar herramienta gráfica
git mergetool
6.2. Estrategias de Merge
# Favorecer versión actual
git merge -X ours feature-branch
# Favorecer versión entrante
git merge -X theirs feature-branch
# Estrategia recursiva (por defecto)
git merge -s recursive feature-branch
7. Automatización y Hooks
7.1. Git Hooks Útiles
Pre-commit hook (.git/hooks/pre-commit):
#!/bin/sh
# Ejecutar tests antes de commit
npm test
if [ $? -ne 0 ]; then
echo "Tests fallaron. Commit cancelado."
exit 1
fi
Pre-push hook (.git/hooks/pre-push):
#!/bin/sh
# Verificar que estamos en la rama correcta
branch=$(git rev-parse --abbrev-ref HEAD)
if [ "$branch" = "main" ]; then
echo "No puedes hacer push directo a main"
exit 1
fi
7.2. Herramientas de Automatización
# Husky para hooks de Node.js
npm install --save-dev husky
# Configurar hook
npx husky add .husky/pre-commit "npm test"
8. Mejores Prácticas
8.1. Nomenclatura de Ramas
feature/JIRA-123-nueva-funcionalidad
bugfix/JIRA-456-corregir-login
hotfix/1.2.1-seguridad-critica
release/2.0.0
8.2. Mensajes de Commit Semánticos
feat: añadir nueva funcionalidad de búsqueda
fix: corregir error en validación de formulario
docs: actualizar documentación de API
style: formatear código según estándares
refactor: reestructurar módulo de autenticación
test: añadir tests para componente principal
chore: actualizar dependencias
8.3. Configuración Recomendada
# Configuración global útil
git config --global pull.rebase true
git config --global rebase.autoStash true
git config --global branch.autosetupmerge always
git config --global branch.autosetuprebase always
9. Comparación de Estrategias
| Estrategia | Complejidad | Casos de Uso | Ventajas | Desventajas |
|---|---|---|---|---|
| Git Flow | Alta | Proyectos con releases programados | Muy organizado, ideal para equipos grandes | Complejo, puede ser excesivo para proyectos simples |
| GitHub Flow | Baja | Desarrollo continuo, despliegue frecuente | Simple, flexible | Menos estructura para proyectos complejos |
| GitLab Flow | Media | Balance entre estructura y simplicidad | Flexible con environments | Requiere disciplina del equipo |
10. Herramientas Complementarias
10.1. Visualización de Ramas
# Ver historial gráfico
git log --oneline --graph --all
# Alias útil
git config --global alias.tree "log --oneline --graph --all --decorate"
10.2. Limpieza de Ramas
# Eliminar ramas fusionadas localmente
git branch --merged | grep -v main | xargs git branch -d
# Eliminar referencias a ramas remotas eliminadas
git remote prune origin
11. Resumen de Comandos Git Flow
| Comando | Uso |
|---|---|
git flow init |
Inicializa Git Flow en el repositorio |
git flow feature start <nombre> |
Crea nueva rama feature |
git flow feature finish <nombre> |
Finaliza y fusiona feature |
git flow release start <version> |
Crea rama release |
git flow release finish <version> |
Finaliza release y crea tag |
git flow hotfix start <version> |
Crea rama hotfix |
git flow hotfix finish <version> |
Finaliza hotfix |
12. Conclusión
La elección de la estrategia de ramificación depende de varios factores: tamaño del equipo, frecuencia de releases, complejidad del proyecto y cultura organizacional. Git Flow es excelente para proyectos con releases planificados, mientras que GitHub Flow es ideal para desarrollo continuo y despliegue frecuente.
Las herramientas como rebase interactivo, hooks y automatización pueden mejorar significativamente la calidad y eficiencia del flujo de trabajo, independientemente de la estrategia elegida.
Siguiente: 7. Resolución de Problemas y Recuperación de Datos
Ejercicios
6.1 — Implementa un flujo Git Flow básico desde cero: crea las ramas main, develop, feature/login, haz merge de feature a develop, crea una rama release/1.0.0, etiqueta el merge a main como v1.0.0.
6.2 — Crea un hook pre-commit que impida hacer commit si hay archivos .log en el staging area. Prueba que funciona intentando añadir un error.log.
6.3 — Crea un escenario con una rama feature que tenga 3 commits sobre main. Genera el merge con --no-ff y el mismo escenario con rebase. Compara los historiales con git log --oneline --graph.
6.4 — Tienes una rama con 5 commits: 2 wip, 1 fix de typo, 1 feat real y 1 docs. Usa rebase -i para limpiarla: squash de los wip con el feat, fixup del typo con el feat, dejando solo 2 commits (feat + docs).
Soluciones
6.1
git init proyecto && cd proyecto
echo "v0" > app.txt && git add . && git commit -m "chore: initial commit"
# Crear develop
git checkout -b develop
# Feature
git checkout -b feature/login
echo "login()" > login.js && git add . && git commit -m "feat: add login"
git checkout develop
git merge --no-ff feature/login -m "merge: feature/login into develop"
# Release
git checkout -b release/1.0.0
echo "1.0.0" > VERSION && git add . && git commit -m "chore: bump to 1.0.0"
# Merge a main y tag
git checkout main
git merge --no-ff release/1.0.0 -m "release: 1.0.0"
git tag -a v1.0.0 -m "Version 1.0.0"
# Merge de vuelta a develop
git checkout develop
git merge release/1.0.0
git branch -d release/1.0.0
6.2
# Crear hook
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/sh
if git diff --cached --name-only | grep -q '\.log$'; then
echo "ERROR: No puedes hacer commit de archivos .log"
exit 1
fi
EOF
chmod +x .git/hooks/pre-commit
# Prueba
echo "error" > error.log
git add error.log
git commit -m "test"
# ERROR: No puedes hacer commit de archivos .log
6.3
# Escenario base
git checkout -b base-merge main
git checkout -b feature-merge base-merge
for i in 1 2 3; do echo "$i" > "f$i.txt" && git add . && git commit -m "feat: $i"; done
# MERGE
git checkout base-merge
git merge --no-ff feature-merge -m "merge: feature"
git log --oneline --graph
# * merge: feature
# |# | * feat: 3
# | * feat: 2
# | * feat: 1
# |/
# REBASE (escenario equivalente)
git checkout -b base-rebase main
git checkout -b feature-rebase base-rebase
for i in 1 2 3; do echo "$i" > "g$i.txt" && git add . && git commit -m "feat: $i"; done
git checkout feature-rebase
git rebase base-rebase
git checkout base-rebase
git merge feature-rebase # fast-forward
git log --oneline --graph
# * feat: 3
# * feat: 2
# * feat: 1
# Historial lineal, sin commit de merge
6.4
git log --oneline
# e feat: docs
# d feat: función principal
# c fix: typo en variable
# b wip: más lógica
# a wip: inicio
git rebase -i HEAD~5
# Cambiar a:
# pick a wip: inicio → (será squash)
# squash b wip: más lógica
# squash c fix: typo en variable → fixup
# pick d feat: función principal
# pick e feat: docs
# Resultado: 2 commits
git log --oneline
# xyz feat: docs
# abc feat: función principal (absorbe los wip y el typo)