Merge vs rebase: cuál usar y la regla que no puedes romper

Merge vs rebase sin dogmatismo: qué hace cada uno a tu historial, la regla de oro del rebase y un flujo de equipo que puedes copiar el lunes.

Merge vs rebase: cuál usar y la regla que no puedes romper

Cada vez que alguien menciona rebase en una PR, mucha gente se pone nerviosa. Han oído “nunca rebasees” por un lado y “el historial tiene que estar limpio” por otro, y las dos frases parecen contradecirse. No lo hacen. El debate merge vs rebase casi nunca es una elección de bando: son operaciones que resuelven problemas distintos, y un equipo sano usa las dos. El miedo viene de un solo punto real, y aquí te lo dejo claro para que el lunes sepas exactamente cuándo cada una toca tu historial.

¿Qué hace realmente cada uno con tu historial?

Merge crea un commit nuevo, el commit de fusión, que tiene dos padres y une dos líneas de trabajo en una. Rebase hace algo distinto: coge tus commits, los quita temporalmente y los vuelve a aplicar uno a uno encima de otra base, generando commits nuevos con hashes nuevos.

Esa diferencia es todo lo que importa. Con merge, los commits originales siguen intactos y aparece uno extra que los junta. Con rebase, los commits originales se sustituyen por copias reescritas. Mismo contenido, hash distinto.

Mira la secuencia de un merge. Estás en feature, quieres integrarlo en main:

# Integrar feature dentro de main con un commit de fusión
git switch main
git merge feature
# Aparece un commit nuevo tipo "Merge branch 'feature'" con dos padres.
# Los commits de feature conservan sus hashes originales.

Uso git switch para cambiar de rama en lugar de git checkout. git switch ya no está marcado como experimental y es el comando específico para moverte entre ramas. checkout sigue funcionando, pero hace demasiadas cosas a la vez y es fácil confundirse.

Ahora el rebase de esa misma feature sobre la última main:

# Reaplicar los commits de feature encima de la punta actual de main
git switch feature
git rebase main
# Antes:  a1b2c3d -> 4d5e6f7  (tus dos commits en feature)
# Después: 9f8e7d6 -> 2c1b3a4  (mismo cambio, HASHES NUEVOS)

Los hashes cambian porque un commit incluye a su padre en el cálculo del identificador. Al cambiar la base, cambia el padre, y con él el hash de cada commit posterior. Es la consecuencia directa de mover el punto de partida, nada más. Si quieres el detalle completo de la operación, tienes el paso a paso de git rebase; para el lado contrario, cómo funciona git merge por dentro.

Diagrama comparando merge y rebase sobre los mismos dos commits de una rama feature. A la izquierda, merge: dos lineas de commits paralelas, main y feature, que se unen en un commit de fusion con dos padres; los commits originales de feature conservan sus hashes. A la derecha, rebase: una unica linea de commits donde los mismos cambios de feature aparecen reaplicados encima de main con hashes nuevos.
Mismos dos commits, dos resultados distintos: merge los conserva y los une con un commit de fusion de dos padres; rebase los reaplica sobre main generando hashes nuevos en una linea recta.

Entonces, ¿cuál deja el historial “más limpio”?

Depende de qué entiendas por limpio, y ahí está la trampa de casi todos los tutoriales que toman partido. Rebase te da un historial lineal: una sola fila de commits, sin bifurcaciones, muy fácil de leer con git log --oneline. Merge te da un historial ramificado, con sus commits de fusión, que preserva en qué rama y en qué momento se hizo cada cosa.

Ninguno es objetivamente mejor. Un historial lineal se lee de un vistazo, pero borra la topología: pierdes la señal de qué commits formaban parte de la misma unidad de trabajo. Un historial con merges cuenta la verdad de cómo pasaron las cosas, a cambio de un grafo más enredado cuando hay muchas ramas vivas a la vez.

MergeRebase
Qué hace al grafoUne dos líneas con un commit de fusión de dos padresReaplica tus commits sobre una nueva base, historial lineal
HashesLos commits originales conservan su hashGenera commits nuevos con hashes nuevos
LegibilidadPreserva contexto: rama y momento de cada cambioLineal y fácil de seguir de arriba abajo
Ramas compartidasSeguro: no reescribe lo que otros ya tienenPeligroso si la rama ya la ha bajado alguien
Cuándo elegirloIntegrar ramas ya compartidas, conservar la historia realOrdenar tu trabajo local antes de publicarlo

La fila que de verdad decide es la de ramas compartidas. Y de ahí sale la única regla que no admite discusión.

La regla de oro: no rebasees lo que ya has compartido

Nunca reescribas commits que ya has empujado a un sitio del que otras personas pueden haber bajado. Esta es la regla de oro del rebase, y es la que resuelve la contradicción entre “nunca rebasees” y “mantén el historial limpio”.

Piensa en el mecanismo. Cuando rebaseas, sustituyes commits por copias con hashes nuevos. Si esos commits solo existían en tu máquina, no pasa nada: nadie más los tenía. Pero si ya los habías compartido y un compañero los tiene en su clon, el remoto y su copia ahora divergen. Para publicar tu versión reescrita te ves obligado a un push forzado, y en cuanto tu compañero haga git pull tendrá dos historias del mismo trabajo peleándose. Le has roto su copia.

Por eso la frase completa no es “nunca rebasees”, es “no rebasees lo que ya es de todos”. Rebasear tu propia rama local antes de compartirla es perfectamente seguro y muy recomendable. Rebasear main porque no te gusta cómo quedó el merge de ayer es una forma rápida de que el equipo deje de hablarte.

Arbol de decision de la regla de oro del rebase. Pregunta: alguien mas ha bajado ya esta rama. Si la respuesta es no, la rama es solo local, el camino lleva a rebasear en verde, marcado como seguro. Si la respuesta es si, la rama ya es compartida, el camino lleva a rebasear en rojo, marcado como peligroso porque obliga a un push forzado que rompe la copia de los demas.
La regla de oro en una decision: rebasear tu rama local es seguro; rebasear una rama que otros ya han bajado los obliga a reconciliar un historial reescrito.

¿Y git pull --rebase?

git pull --rebase es el uso seguro y cotidiano del rebase, porque solo reordena tu trabajo local que todavía no has publicado. Un git pull normal baja los commits del remoto y los fusiona con los tuyos creando un commit de merge cuando ambas ramas han avanzado. Con --rebase, en vez de fusionar, reaplica tus commits locales encima de lo que acabas de bajar.

# Traer lo nuevo del remoto y reaplicar TUS commits locales encima
git pull --rebase
# tus commits locales (aún no publicados) se recolocan sobre origin/main
git push

El resultado es que evitas ese commit de merge “Merge branch ‘main’ of…” que aparece cada vez que dos personas trabajan sobre la misma rama y ensucia el historial sin aportar nada. Como los commits que estás recolocando son solo tuyos y aún no los ha visto nadie, no rompes la regla de oro. Es rebase, pero del bueno.

¿Qué convención adopta tu equipo?

La decisión merge vs rebase casi nunca es tuya en solitario: la fija la convención del equipo, y tu trabajo es ser coherente con ella. Al integrar una PR en GitHub tienes tres botones, y cada uno hace algo distinto con el historial (GitLab y otras plataformas ofrecen mecanismos equivalentes con otros nombres):

  • Merge commit: integra la rama con un commit de fusión y conserva todos los commits de la PR tal cual, con su ramificación.
  • Rebase and merge: reaplica los commits de la PR sobre la base de destino sin crear commit de fusión, dejando el historial lineal.
  • Squash and merge: colapsa todos los commits de la PR en uno solo antes de integrarlo, así que en main cada PR es un único commit.

No hay un ganador universal. Equipos que quieren trazabilidad fina eligen merge commits, y equipos que quieren un main legible de una PR por línea eligen squash. Mezclar convenciones sin acordarlo es lo que sale caro, porque entonces el historial deja de contar una historia coherente y nadie sabe qué esperar al revisar. Pregunta cuál usa tu repo antes de tocar el botón.

Un flujo concreto que puedes copiar el lunes

Aquí tienes el flujo que combina las dos operaciones sin romper nada. Rebase en local para ordenar tu propio trabajo, merge (vía PR) para integrarlo en main.

# 1. Trabaja en tu rama y ordénala mientras sea SOLO tuya
git switch -c feature/login
# ...commits...
git pull --rebase origin main   # mantente al día sobre main sin merges basura

# 2. Sube y abre la PR; a partir de aquí la rama es "compartida"
git push -u origin feature/login

# 3. La PR se integra con la convención del equipo (merge/rebase/squash)

El punto que evita casi todos los sustos es el orden: rebaseas mientras la rama vive solo en tu máquina, y a partir del git push que abre la PR dejas de reescribir su historia. Si necesitas actualizar la PR con lo último de main, muchos equipos prefieren que hagas merge de main en tu rama en vez de rebasear, precisamente para no forzar. Coordínalo.

Hay un caso legítimo donde sí rebaseas una rama ya publicada: tu propia rama de PR, cuando de verdad nadie más ha bajado ese trabajo. Entonces tras el rebase toca forzar:

# Solo en TU rama de PR, cuando nadie más la ha bajado
git push --force-with-lease

Usa --force-with-lease, no --force a secas. --force-with-lease aborta el push si el remoto tiene commits que tú no habías visto todavía, porque compara la punta remota con tu rama de seguimiento local. --force no comprueba nada y pisa lo que haya. Que sea más seguro no lo convierte en la única forma segura de forzar. Es simplemente la opción con red de seguridad, y por eso deberías escribirla por defecto.

Antes de llevarte este flujo al repo del equipo, comprueba que distingues de un vistazo qué operación reescribe historia y cuál no. Pruébalo tú en este ejercicio interactivo, decidiendo caso a caso cuándo toca merge y cuándo rebase:

Cargando ejercicio...

Errores comunes

Rebasear una rama que otro ya ha bajado. Es la forma número uno de romper la regla de oro. En cuanto reescribes commits que un compañero tiene en su clon, lo condenas a resolver una divergencia que tú provocaste. Si dudas de si alguien la tiene, asume que sí.

Usar --force en lugar de --force-with-lease. El primero pisa cualquier cosa que haya en el remoto, incluidos commits que un compañero acaba de subir a tu rama de PR mientras tú rebaseabas. El segundo se planta y te avisa. Cambiar de uno a otro cuesta once caracteres.

Creer que rebase “borra” commits. No los borra. Crea copias nuevas y deja las originales colgando, accesibles en el reflog durante un tiempo antes de que la recolección de basura de Git las limpie. Por eso un rebase que sale mal casi siempre se puede deshacer.

Mezclar convenciones dentro del mismo repo. Un día squash, otro día merge commit, otro rebase-and-merge, sin haberlo hablado. Lo que vuelve ilegible el historial es la falta de acuerdo, más que cualquier operación concreta. La coherencia vale más que la opción “correcta”.

Estos cuatro errores comparten raíz: pasan cuando reescribes historia que ya no era solo tuya. Si tienes clara la frontera entre “mi trabajo local” y “trabajo compartido”, casi ninguno te ocurre. Y si quieres reforzar los cimientos de todo esto, la guía completa de ramas en Git cubre el modelo mental de ramas sobre el que descansan merge y rebase.

Preguntas Frecuentes

¿Rebase borra mis commits?

No. Crea copias nuevas y deja las originales accesibles en el reflog un tiempo.

¿Puedo deshacer un rebase?

Sí. Localiza con git reflog la línea justo anterior al rebase y vuelve a ella:

git reflog                 # busca el HEAD de antes del rebase
git reset --hard <hash>    # recupera el estado original

Como el rebase no borró los commits originales, el reset los recupera enteros mientras sigan en el reflog.

¿git pull hace merge o rebase?

Por defecto hace merge: baja los commits del remoto y los fusiona con los tuyos, creando un commit de fusión si ambos han avanzado. Si prefieres rebase, usa git pull --rebase puntualmente, o fija git config pull.rebase true para que ese sea el comportamiento por defecto en el repo.

¿Squash cuenta como merge o como rebase?

Es una opción de integración aparte. Squash colapsa todos los commits de una rama en un único commit al integrarla, de modo que en main cada PR aparece como un solo commit. Es una tercera forma de resolver cómo entra el trabajo en la rama principal, distinta tanto del merge commit clásico como del rebase-and-merge.

¿La regla de oro admite excepciones?

Sí, una: cuando de verdad nadie más ha bajado la rama. Si es tu rama de PR y estás seguro de que ningún compañero la tiene en local, puedes rebasear y forzar con --force-with-lease. La clave es la certeza. Ante la duda, coordínalo con quien pueda estar tocándola antes de reescribir nada.

¿Quieres dominar merge, rebase y el flujo de PR con las manos en vez de leerlo? El curso Git de cero a profesional recorre estas decisiones de forma visual e interactiva: resuelves conflictos, ordenas historiales y practicas la regla de oro sin miedo a romperle el repo a nadie.

Un concepto nuevo cada semana