Los equipos gastan horas debatiendo rebase vs. merge como si fuera cuestión moral. No lo es. Son herramientas con trade-offs distintos. El problema no es elegir una. Es no entender cuándo usar cada una.
Qué hace cada uno
Merge crea un nuevo commit que combina el historial de dos branches. Preserva el historial exactamente como ocurrió, con todos sus commits de feature y el commit de merge.
# merge
* merge branch 'feature' into main
|\
| * add user validation
| * create user model
|/
* main commit
Rebase reaplica los commits de un branch sobre el otro. El historial queda lineal, como si los commits hubieran sido hechos en secuencia.
# rebase
* add user validation
* create user model
* main commit
Cuándo usar merge
Merge es la elección correcta cuando:
- El branch tiene múltiples autores y el historial de contribución importa
- Quieres preservar el contexto de cuándo ocurrieron los cambios
- El branch es long-lived (ej: release branch que vive semanas)
- Estás trabajando con Git Flow o modelo similar
En GitHub/GitLab, merge vía pull request es el estándar. Crea un merge commit que documenta cuándo entró el código, quién lo revisó y el contexto del cambio.
Cuándo usar rebase
Rebase es la elección correcta cuando:
- El branch es corto (1-3 commits) y quieres mantener el historial limpio
- Necesitas actualizar tu branch con cambios de main sin crear merge commits innecesarios
- El equipo prefiere un historial lineal para navegar con
git log --oneline - Estás preparando commits para squash merge
# Actualiza branch con cambios de main vía rebase
git fetch origin
git rebase origin/main
# Si hay conflicto, resuélvelo y continúa
git rebase --continue
La regla de oro: no hagas rebase de branches públicos
Rebase reescribe historial. Si otro desarrollador está trabajando en el mismo branch, rebase crea un historial divergente que fuerza force push y causa confusión.
Haz rebase solo de branches que sean solo tuyos. Si el branch es compartido, usa merge.
Squash merge: lo mejor de ambos mundos
Muchos equipos adoptaron squash merge como estándar: los commits de la feature se comprimen en un único commit antes del merge a main.
# En GitHub, configúralo en repo Settings > General > Pull Requests
# ☑ Allow squash merging
# O vía CLI:
git checkout main
git merge --squash feature-branch
git commit -m "feat(auth): add JWT refresh token rotation"
Ventajas: el historial de main queda limpio con un commit por feature. Desventajas: el historial detallado de la feature (decisiones, discusiones, intentos) se pierde.
El flujo que funciona en la práctica
# 1. Crea branch a partir de main
git checkout main && git pull
git checkout -b feature/user-validation
# 2. Trabaja, haz commits localmente
git add . && git commit -m "feat: add user model"
git commit -m "feat: add validation logic"
# 3. Antes de abrir PR, rebase sobre main
git fetch origin
git rebase origin/main
# 4. Resuelve conflictos si hay
git rebase --continue
# 5. Abre PR: squash merge en GitHub
Esto da lo mejor de ambos mundos: rebase mantiene tu branch actualizado sin merge commits, y squash merge mantiene el historial de main limpio.
Lo que no hacer
No hagas force push en branches compartidos. No hagas rebase de commits que ya fueron pusheados y que otras personas están usando. No hagas rebase interactivo en branches públicos. Y no discutas esto en Slack como si fuera religión. Elige la herramienta que funciona para el contexto de tu equipo.
¿Te gustó el contenido?
Construyo productos web y soluciones con IA de la manera correcta — arquitectura sólida, código sostenible y entrega real.
Hablemos