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:

1.2. Tipos de Ramas Comunes

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:

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:

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:

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)