Rebase
Aprende a utilizar git rebase para mantener un historial de proyecto limpio y lineal, reorganizando commits y facilitando la integración de cambios entre ramas.
Cristian Escalante
Última actualización: 3 de mayo de 2025
Rebase
Git ofrece dos formas principales de integrar cambios entre ramas: merge y rebase. Mientras que el merge preserva el historial completo y crea un commit de fusión, el rebase reescribe el historial para crear una línea de tiempo más limpia y lineal. En esta lección, exploraremos en profundidad el comando git rebase
, sus usos, opciones avanzadas y las mejores prácticas para utilizarlo correctamente.
¿Qué es rebase?
Rebase es una operación que "trasplanta" una serie de commits de una rama a otra, cambiando la base de la rama. En lugar de crear un commit de fusión como lo hace git merge
, rebase reaplica los commits uno por uno sobre la nueva base, creando nuevos commits con contenido idéntico pero con diferentes hashes.
Merge vs Rebase: Diferencias conceptuales
# Antes de cualquier operación:
A---B---C (feature)
/
D---E---F---G (main)
# Después de merge:
A---B---C (feature)
/ \
D---E---F---G---H (main, H es un commit de merge)
# Después de rebase:
A'--B'--C' (feature)
/
D---E---F---G (main)
En el caso del rebase, los commits A, B y C se reaplican sobre G, creando nuevos commits A', B' y C' con el mismo contenido pero diferentes hashes.
Rebase básico
La sintaxis básica de rebase es:
git checkout feature
git rebase main
Este comando:
- Guarda temporalmente los commits de la rama
feature
que no están enmain
- Resetea la rama
feature
para que apunte amain
- Reaplica los commits guardados uno por uno
Ejemplo práctico
# Situación inicial: estás en la rama feature con algunos commits
git checkout feature
# Haces algunos commits...
# Para integrar los últimos cambios de main
git rebase main
# Si hay conflictos, los resuelves y continúas
git add .
git rebase --continue
# Cuando terminas, puedes actualizar main con un fast-forward merge
git checkout main
git merge feature # Será un fast-forward merge
Resolución de conflictos durante rebase
Durante un rebase, Git puede encontrar conflictos al replicar los commits. El proceso para resolverlos es:
- Git pausa el rebase cuando encuentra un conflicto
- Tú resuelves los conflictos manualmente
- Añades los archivos resueltos con
git add
- Continúas el rebase con
git rebase --continue
Si en algún momento quieres cancelar el rebase:
git rebase --abort
Rebase interactivo
El rebase interactivo es una de las características más poderosas de Git, permitiéndote modificar commits mientras los reaplicas:
git rebase -i main
# o para modificar los últimos N commits
git rebase -i HEAD~3
Esto abrirá un editor con una lista de commits y opciones:
pick abc1234 Add feature X
pick def5678 Fix typo in README
pick ghi9101 Update documentation
# Rebase instructions...
Opciones del rebase interactivo
- pick: Usar el commit tal cual
- reword: Usar el commit, pero editar su mensaje
- edit: Usar el commit, pero detener el rebase para modificarlo
- squash: Combinar el commit con el anterior
- fixup: Como squash, pero descartar el mensaje del commit
- drop: Eliminar el commit
Casos de uso comunes
Reordenar commits
Simplemente cambia el orden de las líneas:
pick ghi9101 Update documentation
pick abc1234 Add feature X
pick def5678 Fix typo in README
Combinar commits
pick abc1234 Add feature X
squash def5678 Fix typo in README
squash ghi9101 Update documentation
Esto combinará los tres commits en uno solo, y te permitirá editar el mensaje del commit resultante.
Dividir un commit
edit abc1234 Add feature X
Cuando el rebase se detenga:
git reset HEAD^ # Deshacer el commit pero mantener los cambios
git add parte1.js
git commit -m "Add part 1 of feature X"
git add parte2.js
git commit -m "Add part 2 of feature X"
git rebase --continue
Eliminar commits
pick abc1234 Add feature X
drop def5678 Commit to be removed
pick ghi9101 Update documentation
Casos de uso avanzados
Rebase onto
El comando git rebase --onto
permite trasplantar una serie de commits a una base diferente:
git rebase --onto <nueva-base> <commit-inicio> <commit-fin>
Ejemplo:
# Mover commits de una rama a otra
git rebase --onto main feature~3 feature
Rebase con autosquash
Puedes marcar commits para ser automáticamente combinados durante un rebase interactivo:
# Hacer un commit que se combinará con el commit abc1234
git commit --fixup abc1234
# Más tarde, hacer el rebase con autosquash
git rebase -i --autosquash main
Rebase con autostash
Si tienes cambios sin confirmar, puedes usar la opción --autostash
:
git rebase --autostash main
Esto guardará automáticamente tus cambios con stash antes del rebase y los aplicará después.
La regla de oro del rebase
Nunca hagas rebase en ramas públicas/compartidas
Rebase reescribe el historial, creando nuevos commits con nuevos hashes. Si otros desarrolladores ya tienen los commits originales, esto causará problemas de sincronización.
Cuándo usar rebase
- Para mantener tu rama de característica actualizada con la rama principal
- Para limpiar tu historial local antes de compartirlo
- Para integrar cambios de una rama de característica en la rama principal
Cuándo NO usar rebase
- En ramas que ya han sido publicadas y que otros desarrolladores pueden haber clonado
- Cuando quieres preservar el historial exacto de los merges
- Cuando no estás seguro de lo que estás haciendo
Configuración recomendada
# Configurar pull para usar rebase por defecto
git config --global pull.rebase true
# Habilitar autostash para rebase
git config --global rebase.autoStash true
Flujos de trabajo con rebase
Mantener una rama de característica actualizada
# Mientras trabajas en tu rama de característica
git checkout feature
git rebase main
# Continúa trabajando...
Limpiar una rama antes de integrarla
# Limpiar el historial de la rama
git checkout feature
git rebase -i main
# Squash, reordenar, etc.
# Integrar en main
git checkout main
git merge feature
Rebase en un flujo de trabajo de pull request
# Antes de crear el PR
git checkout feature
git rebase main
git push --force-with-lease # Si ya habías hecho push de la rama
# Después de recibir comentarios en el PR
git commit -m "Address review comments"
git rebase -i HEAD~2 # Combinar con el commit anterior
git push --force-with-lease
Solución de problemas comunes
Conflictos repetitivos
Si encuentras los mismos conflictos repetidamente durante un rebase largo:
# Configurar rerere (reuse recorded resolution)
git config --global rerere.enabled true
Esto hará que Git recuerde cómo resolviste un conflicto y aplique automáticamente la misma resolución si encuentra el mismo conflicto nuevamente.
Recuperar el estado anterior al rebase
Si algo sale mal durante un rebase:
# Durante el rebase
git rebase --abort
# Si ya completaste el rebase
git reflog
git reset --hard HEAD@{5} # Donde HEAD@{5} es el estado antes del rebase
Identificar qué commits han sido rebaseados
# Ver los hashes originales y nuevos
git log --oneline --cherry feature...origin/feature
Mejores prácticas
- Rebase con frecuencia: Mantén tu rama actualizada con la rama principal para minimizar conflictos
- Commits atómicos: Haz commits pequeños y enfocados que faciliten el rebase
- Prueba después del rebase: Asegúrate de que tu código sigue funcionando después de un rebase
- Usa --force-with-lease: En lugar de --force cuando actualices ramas remotas después de un rebase
- Documenta tu flujo de trabajo: Asegúrate de que tu equipo entienda cuándo y cómo usar rebase
Conclusión
El rebase es una herramienta poderosa que te permite mantener un historial de proyecto limpio y lineal. Aunque tiene una curva de aprendizaje más pronunciada que el merge, dominar el rebase te da un control fino sobre el historial de tu proyecto.
Recuerda siempre la regla de oro: nunca hagas rebase en ramas públicas/compartidas. Con esta precaución en mente, el rebase puede convertirse en una parte valiosa de tu flujo de trabajo con Git, ayudándote a mantener un historial de proyecto más organizado y comprensible.