Patrones de Flujo de Trabajo con Git
Mejores prácticas para el control de versiones con Git, estrategias de ramificación y desarrollo colaborativo.
Cuándo Activar
- Configurar el flujo de trabajo con Git para un nuevo proyecto
- Decidir una estrategia de ramificación (GitFlow, trunk-based, GitHub Flow)
- Redactar mensajes de commit y descripciones de PR
- Resolver conflictos de fusión
- Gestionar lanzamientos y etiquetas de versión
- Integrar nuevos miembros del equipo en las prácticas de Git
Estrategias de Ramificación
GitHub Flow (Simple, Recomendado para la Mayoría)
Mejor para despliegue continuo y equipos pequeños a medianos.
main (protegida, siempre desplegable)
│
├── feature/user-auth → PR → fusionar a main
├── feature/payment-flow → PR → fusionar a main
└── fix/login-bug → PR → fusionar a main
Reglas:
mainsiempre es desplegable- Crear ramas de funcionalidad desde
main - Abrir una Solicitud de Pull (PR) cuando esté lista para revisión
- Después de la aprobación y que CI pase, fusionar a
main - Desplegar inmediatamente después de la fusión
Desarrollo Trunk-Based (Equipos de Alta Velocidad)
Mejor para equipos con CI/CD sólido y feature flags.
main (tronco)
│
├── rama efímera (máx. 1-2 días)
├── rama efímera
└── rama efímera
Reglas:
- Todos envían a
maino a ramas muy efímeras - Los feature flags ocultan el trabajo incompleto
- CI debe pasar antes de fusionar
- Desplegar varias veces al día
GitFlow (Complejo, Orientado a Ciclos de Lanzamiento)
Mejor para lanzamientos programados y proyectos empresariales.
main (lanzamientos de producción)
│
└── develop (rama de integración)
│
├── feature/user-auth
├── feature/payment
│
├── release/1.0.0 → fusionar a main y develop
│
└── hotfix/critical → fusionar a main y develop
Reglas:
maincontiene solo código listo para produccióndevelopes la rama de integración- Las ramas de funcionalidad parten de
develop, se fusionan de vuelta adevelop - Las ramas de lanzamiento parten de
develop, se fusionan amainydevelop - Las ramas de hotfix parten de
main, se fusionan amainydevelop
Cuándo Usar Cada Una
| Estrategia | Tamaño del Equipo | Cadencia de Lanzamiento | Mejor Para |
|---|---|---|---|
| GitHub Flow | Cualquiera | Continuo | SaaS, aplicaciones web, startups |
| Trunk-Based | 5+ experimentados | Varias/día | Equipos de alta velocidad, feature flags |
| GitFlow | 10+ | Programado | Empresas, industrias reguladas |
Mensajes de Commit
Formato de Commits Convencionales
<tipo>(<ámbito>): <asunto>
[cuerpo opcional]
[pie(s) opcional(es)]
Tipos
| Tipo | Uso | Ejemplo |
|---|---|---|
feat | Nueva funcionalidad | feat(auth): agregar inicio de sesión OAuth2 |
fix | Corrección de errores | fix(api): manejar respuesta nula en endpoint de usuario |
docs | Documentación | docs(readme): actualizar instrucciones de instalación |
style | Formato, sin cambio de código | style: corregir indentación en componente de inicio de sesión |
refactor | Refactorización de código | refactor(db): extraer pool de conexiones a módulo |
test | Agregar/actualizar pruebas | test(auth): agregar pruebas unitarias para validación de token |
chore | Tareas de mantenimiento | chore(deps): actualizar dependencias |
perf | Mejora de rendimiento | perf(query): agregar índice a tabla de usuarios |
ci | Cambios en CI/CD | ci: agregar servicio PostgreSQL al flujo de pruebas |
revert | Revertir commit anterior | revert: revertir "feat(auth): agregar inicio de sesión OAuth2" |
Ejemplos Buenos vs Malos
# MALO: Vago, sin contexto
git commit -m "cosas arregladas"
git commit -m "actualizaciones"
git commit -m "WIP"
# BUENO: Claro, específico, explica por qué
git commit -m "fix(api): reintentar solicitudes en 503 Servicio No Disponible
La API externa ocasionalmente devuelve errores 503 durante horas pico.
Se agregó lógica de reintento con backoff exponencial y máximo de 3 intentos.
Cierra #123"
Plantilla de Mensaje de Commit
Crear .gitmessage en la raíz del repositorio:
# <tipo>(<ámbito>): <asunto>
# # Tipos: feat, fix, docs, style, refactor, test, chore, perf, ci, revert
# Ámbito: api, ui, db, auth, etc.
# Asunto: modo imperativo, sin punto, máximo 50 caracteres
#
# [cuerpo opcional] - explicar el por qué, no el qué
# [pie opcional] - Cambios importantes, cierra #issue
Habilitar con: git config commit.template .gitmessage
Fusión vs Rebase
Fusión (Preserva el Historial)
# Crea un commit de fusión
git checkout main
git merge feature/user-auth
# Resultado:
# * commit de fusión
# |\
# | * commits de funcionalidad
# |/
# * commits de main
Úsalo cuando:
- Fusiones ramas de funcionalidad a
main - Quieras preservar el historial exacto
- Varias personas hayan trabajado en la rama
- La rama haya sido enviada y otros puedan haber basado su trabajo en ella
Rebase (Historial Lineal)
# Reescribe los commits de la rama de funcionalidad sobre la rama destino
git checkout feature/user-auth
git rebase main
# Resultado:
# * commits de funcionalidad (reescritos)
# * commits de main
Úsalo cuando:
- Actualices tu rama local de funcionalidad con la última versión de
main - Quieras un historial limpio y lineal
- La rama sea solo local (no enviada)
- Seas el único trabajando en la rama
Flujo de Trabajo con Rebase
# Actualizar rama de funcionalidad con la última versión de main (antes del PR)
git checkout feature/user-auth
git fetch origin
git rebase origin/main
# Arreglar cualquier conflicto
# Las pruebas aún deben pasar
# Forzar el envío (solo si eres el único contribuidor)
git push --force-with-lease origin feature/user-auth
Cuándo NO Hacer Rebase
# NUNCA hagas rebase a ramas que:
- Hayan sido enviadas a un repositorio compartido
- Otras personas hayan usado como base para su trabajo
- Sean ramas protegidas (main, develop)
- Ya estén fusionadas
# Por qué: Rebase reescribe el historial, rompiendo el trabajo de otros
Flujo de Trabajo de Pull Request
Formato del Título del PR
<tipo>(<ámbito>): <descripción>
Ejemplos:
feat(auth): agregar soporte SSO para usuarios empresariales
fix(api): resolver condición de carrera en procesamiento de pedidos
docs(api): agregar especificación OpenAPI para endpoints v2
Plantilla de Descripción del PR
## Qué
Breve descripción de lo que hace este PR.
## Por qué
Explicar la motivación y el contexto.
## Cómo
Detalles clave de implementación que vale la pena destacar.
## Pruebas
- [ ] Pruebas unitarias agregadas/actualizadas
- [ ] Pruebas de integración agregadas/actualizadas
- [ ] Pruebas manuales realizadas
## Capturas de Pantalla (si aplica)
Capturas de antes/después para cambios en la UI.
## Lista de Verificación
- [ ] El código sigue las guías de estilo del proyecto
- [ ] Se completó la auto-revisión
- [ ] Se agregaron comentarios para lógica compleja
- [ ] Se actualizó la documentación
- [ ] No se introdujeron nuevas advertencias
- [ ] Las pruebas pasan localmente
- [ ] Se enlazaron issues relacionados
Cierra #123
Lista de Verificación para Revisión de Código
Para Revisores:
- ¿El código resuelve el problema planteado?
- ¿Hay casos límite no manejados?
- ¿El código es legible y mantenible?
- ¿Hay suficientes pruebas?
- ¿Hay problemas de seguridad?
- ¿El historial de commits está limpio (squashed si es necesario)?
Para Autores:
- Se completó la auto-revisión antes de solicitar revisión
- CI pasa (pruebas, lint, typecheck)
- El tamaño del PR es razonable (<500 líneas ideal)
- Relacionado con una sola funcionalidad/corrección
- La descripción explica claramente el cambio
Resolución de Conflictos
Identificar Conflictos
# Verificar conflictos antes de fusionar
git checkout main
git merge feature/user-auth --no-commit --no-ff
# Si hay conflictos, Git mostrará:
# CONFLICTO (contenido): Conflicto de fusión en src/auth/login.ts
# La fusión automática falló; arregla los conflictos y luego haz commit del resultado.
Resolver Conflictos
# Ver archivos en conflicto
git status
# Ver marcadores de conflicto en el archivo
# <<<<<<< HEAD
# contenido de main
# =======
# contenido de la rama de funcionalidad
# >>>>>>> feature/user-auth
# Opción 1: Resolución manual
# Editar archivo, eliminar marcadores, mantener contenido correcto
# Opción 2: Usar herramienta de fusión
git mergetool
# Opción 3: Aceptar un lado
git checkout --ours src/auth/login.ts # Mantener versión de main
git checkout --theirs src/auth/login.ts # Mantener versión de funcionalidad
# Después de resolver, preparar y hacer commit
git add src/auth/login.ts
git commit
Estrategias para Prevenir Conflictos
# 1. Mantener las ramas de funcionalidad pequeñas y de corta duración
# 2. Hacer rebase frecuentemente sobre main
git checkout feature/user-auth
git fetch origin
git rebase origin/main
# 3. Comunicarse con el equipo sobre la modificación de archivos compartidos
# 4. Usar feature flags en lugar de ramas de larga duración
# 5. Revisar y fusionar PRs rápidamente
Gestión de Ramas
Convenciones de Nomenclatura
# Ramas de funcionalidad
feature/user-authentication
feature/JIRA-123-payment-integration
# Correcciones de errores
fix/login-redirect-loop
fix/456-null-pointer-exception
# Hotfixes (problemas de producción)
hotfix/critical-security-patch
hotfix/database-connection-leak
# Lanzamientos
release/1.2.0
release/2024-01-hotfix
# Experimentos/POCs
experiment/new-caching-strategy
poc/graphql-migration
Limpieza de Ramas
# Eliminar ramas locales que están fusionadas
git branch --merged main | grep -v "^\*\|main" | xargs -n 1 git branch -d
# Eliminar referencias de seguimiento remoto de ramas eliminadas
git fetch -p
# Eliminar rama local
git branch -d feature/user-auth # Eliminación segura (solo si está fusionada)
git branch -D feature/user-auth # Eliminación forzada
# Eliminar rama remota
git push origin --delete feature/user-auth
Flujo de Trabajo con Stash
# Guardar trabajo en progreso
git stash push -m "WIP: autenticación de usuario"
# Listar stashes
git stash list
# Aplicar el stash más reciente
git stash pop
# Aplicar un stash específico
git stash apply stash@{2}
# Eliminar stash
git stash drop stash@{0}
Gestión de Lanzamientos
Versionado Semántico
MAJOR.MINOR.PATCH
MAJOR: Cambios importantes
MINOR: Nuevas funcionalidades, compatible hacia atrás
PATCH: Correcciones de errores, compatible hacia atrás
Ejemplos:
1.0.0 → 1.0.1 (patch: corrección de error)
1.0.1 → 1.1.0 (minor: nueva funcionalidad)
1.1.0 → 2.0.0 (major: cambio importante)
Creación de Lanzamientos
# Crear etiqueta anotada
git tag -a v1.2.0 -m "Lanzamiento v1.2.0
Funcionalidades:
- Agregar autenticación de usuario
- Implementar restablecimiento de contraseña
Correcciones:
- Resolver problema de redirección de inicio de sesión
Cambios Importantes:
- Ninguno"
# Enviar etiqueta al remoto
git push origin v1.2.0
# Listar etiquetas
git tag -l
# Eliminar etiqueta
git tag -d v1.2.0
git push origin --delete v1.2.0
Generación de Changelog
# Generar changelog a partir de commits
git log v1.1.0..v1.2.0 --oneline --no-merges
# O usar conventional-changelog
npx conventional-changelog -i CHANGELOG.md -s
Configuración de Git
Configuraciones Esenciales
# Identidad del usuario
git config --global user.name "Tu Nombre"
git config --global user.email "[email protected]"
# Nombre de rama por defecto
git config --global init.defaultBranch main
# Comportamiento de pull (rebase en lugar de fusión)
git config --global pull.rebase true
# Comportamiento de push (solo la rama actual)
git config --global push.default current
# Corrección automática de errores tipográficos
git config --global help.autocorrect 1
# Mejor algoritmo de diff
git config --global diff.algorithm histogram
# Salida a color
git config --global color.ui auto
Aliases Útiles
# Agregar a ~/.gitconfig
[alias]
co = checkout
br = branch
ci = commit
st = status
unstage = reset HEAD --
last = log -1 HEAD
visual = log --oneline --graph --all
amend = commit --amend --no-edit
wip = commit -m "WIP"
undo = reset --soft HEAD~1
contributors = shortlog -sn
Patrones de Gitignore
# Dependencias
node_modules/
vendor/
# Salidas de compilación
dist/
build/
*.o
*.exe
# Archivos de entorno
.env
.env.local
.env.*.local
# IDE
.idea/
.vscode/
*.swp
*.swo
# Archivos del sistema operativo
.DS_Store
Thumbs.db
# Registros
*.log
logs/
# Cobertura de pruebas
coverage/
# Caché
.cache/
*.tsbuildinfo
Flujos de Trabajo Comunes
Iniciar una Nueva Funcionalidad
# 1. Actualizar la rama main
git checkout main
git pull origin main
# 2. Crear rama de funcionalidad
git checkout -b feature/user-auth
# 3. Hacer cambios y commits
git add .
git commit -m "feat(auth): implementar inicio de sesión OAuth2"
# 4. Enviar al remoto
git push -u origin feature/user-auth
# 5. Crear Pull Request en GitHub/GitLab
Actualizar un PR con Nuevos Cambios
# 1. Hacer cambios adicionales
git add .
git commit -m "feat(auth): agregar manejo de errores"
# 2. Enviar actualizaciones
git push origin feature/user-auth
Sincronizar Fork con el Repositorio Original
# 1. Agregar remoto upstream (una vez)
git remote add upstream https://github.com/original/repo.git
# 2. Obtener upstream
git fetch upstream
# 3. Fusionar upstream/main en tu main
git checkout main
git merge upstream/main
# 4. Enviar a tu fork
git push origin main
Deshacer Errores
# Deshacer el último commit (mantener cambios)
git reset --soft HEAD~1
# Deshacer el último commit (descartar cambios)
git reset --hard HEAD~1
# Deshacer el último commit enviado al remoto
git revert HEAD
git push origin main
# Deshacer cambios en un archivo específico
git checkout HEAD -- ruta/al/archivo
# Corregir el mensaje del último commit
git commit --amend -m "Nuevo mensaje"
# Agregar archivo olvidado al último commit
git add archivo-olvidado
git commit --amend --no-edit
Hooks de Git
Hook Pre-Commit
#!/bin/bash
# .git/hooks/pre-commit
# Ejecutar linting
npm run lint || exit 1
# Ejecutar pruebas
npm test || exit 1
# Verificar secretos
if git diff --cached | grep -E '(password|api_key|secret)'; then
echo "Posible secreto detectado. Commit abortado."
exit 1
fi
Hook Pre-Push
#!/bin/bash
# .git/hooks/pre-push
# Ejecutar suite completa de pruebas
npm run test:all || exit 1
# Verificar declaraciones console.log
if git diff origin/main | grep -E 'console\.log'; then
echo "Elimina las declaraciones console.log antes de enviar."
exit 1
fi
Antipatrones
# MALO: Hacer commit directamente a main
git checkout main
git commit -m "corregir error"
# BUENO: Usar ramas de funcionalidad y PRs
# MALO: Hacer commit de secretos
git add .env # Contiene claves API
# BUENO: Agregar a .gitignore, usar variables de entorno
# MALO: PRs enormes (1000+ líneas)
# BUENO: Dividir en PRs más pequeños y enfocados
# MALO: Mensajes de commit "Actualizar"
git commit -m "actualizar"
git commit -m "corregir"
# BUENO: Mensajes descriptivos
git commit -m "fix(auth): resolver bucle de redirección después del inicio de sesión"
# MALO: Reescribir historial público
git push --force origin main
# BUENO: Usar revert para ramas públicas
git revert HEAD
# MALO: Ramas de funcionalidad de larga duración (semanas/meses)
# BUENO: Mantener ramas cortas (días), hacer rebase frecuentemente
# MALO: Fusionar sin revisión
git merge feature/user-auth # Sin PR, sin revisión de código
# BUENO: Siempre usar PRs con revisión de código
# MALO: Ignorar fallos de CI
git commit --no-verify # Omitir hooks
# BUENO: Arreglar fallos de CI antes de fusionar