mrsaynothing.dev
git merge vs rebase — la decisión en 10 segundos

> git merge vs rebase — la decisión en 10 segundos▋

Merge o rebase, una pregunta decide: ¿el commit salió de tu máquina? La tabla de decisión, el caso fast-forward y el rescate con reflog cuando un rebase sale torcido.

mrsaynothing· 5 de octubre de 2026· 8 min de lectura

Vas a escribir uno de estos dos comandos miles de veces en tu carrera, y media internet lo convierte en religión: rebase todo, la historia debe estar limpia de un lado, nunca rebase, destruye trabajo del otro. Ninguno de los dos bandos menciona la regla real, que cabe en diez segundos. Este post es la decisión, no la teología, y pertenece al cluster Undo Anything in Git — la misma familia que git revert vs reset, el otro par de «dos comandos, una pregunta». Git se escribió de cero en diez días en abril de 2005; el debate merge-vs-rebase lleva corriendo desde entonces.

La lista de cinco minutos

git merge vs rebase — la única pregunta un commit listo para aterrizar git status -sb muestra adelante/atrás ¿alguien más baja esta rama? revisa la rama, no tu instinto git log origin/feature..feature otros la pudieron bajar → es solo tuya → git merge registra lo que de verdad pasó git rebase historia lineal, revisión fácil ¿la historia se ve mal después? git reflog → reset --hard HEAD@{1}
fig 1 — el árbol merge-o-rebase. Haz clic en tu rama.

¿Cuál es la diferencia entre git merge y git rebase?

Ambos comandos entregan el mismo código; discuten sobre qué debe contar la historia después. Merge escribe el desacuerdo: un commit nuevo con dos padres, la divergencia queda registrada para quien lea el grafo más tarde. Rebase finge que empezaste desde la base de hoy: tus tres commits se reescriben como tres commits nuevos con SHAs nuevos, y los viejos quedan inalcanzables desde cualquier rama.

Corrí ambos en un banco desechable con git 2.47.3, mismos cinco commits cada vez. La pasada de merge conservó cada SHA original y añadió un nudo; la pasada de rebase cambió la identidad de los commits de la rama — c3 entró como 5d48940 y salió como 6b2be0a. Mismo árbol, otra historia:

después de merge c1 c2 c3 · c4 c5 commit de merge · 2 padres después de rebase c1 c2 c5 c3' 6b2be0a c4' 67c0442 una línea — sin nudo, los SHAs viejos desaparecieron
fig 2 — mismo árbol, dos historias. Las primas son los mismos cambios con nuevos IDs.

verifica: git log --oneline --graph → un nudo |\ significa merge, una línea recta significa que ganó el rebase

¿Cuándo un merge se vuelve un fast-forward?

Si main no se movió desde que creaste la rama, no hay nada que fusionar — git solo desliza la etiqueta hacia adelante. Eso es un fast-forward, y explica por qué el bando del rebase consigue su línea limpia sin forzar nada: rebase de tu feature sobre main, el merge se vuelve fast-forward y el grafo queda en línea recta. Desde el banco:

* 67c0442 c4 feature 2      # rebased, luego merged — fast-forward
* 6b2be0a c3 feature 1      # SHAs nuevos — 5d48940 antes del rebase
* 1398836 c5 main moved on
* facd5a4 c2 main work
* f45b000 c1 base

Cinco commits, cero nudos. El precio: esos SHAs prima ya no existen en ningún otro sitio que tu máquina. Haz push y el clone de un compañero conserva los originales — dos versiones del commit «igual», exactamente el lío de la quinta sección.

verifica: git merge --ff-only feature → Fast-forward en la salida, sin commit de merge

¿Qué commits siguen siendo solo tuyos?

La respuesta es un comando, no una corazonada. git log origin/main..HEAD lista los commits que origin nunca vio — esos admiten rebase. El espejo, git log origin/main..origin/main, está vacío por definición; el comando que importa revisa la rama sobre la que otros construyen. Si la lista incluye un commit que otro clone ya pueda tener — un push, un pull request abierto, una rama empujada y re-empujada con fuerza — ya no es solo tuyo, diga lo que diga tu grafo local.

El trabajo sin push es justo para lo que existe el rebase: reescríbelo sobre la base actualizada y tu pull request se lee como una secuencia limpia. Por eso «pull con rebase» es un default sano en ramas privadas — git pull --rebase reescribe tus commits locales encima de lo que llegó, en vez de tejer un nudo de merge en cada sincronización. El caso del trabajo en stash vive en git stash a single file; la variante de fork en sync fork with upstream.

¿Qué rompe un rebase en una rama compartida?

Cada clone que guarda los commits viejos pasa a discrepar del tuyo sobre la realidad. El rebase les da SHAs nuevos; tu rama empujada y tu rama reescrita ya no comparten ascendencia, así que el siguiente push exige --force — y todos los que bajaron la versión vieja deben fusionar su copia de commits que «ya no existen». Sus duplicados reaparecen en cada merge futuro. No es un caso teórico: el merge de commits duplicados es el clásico desenlace, y desenredarlo cuesta una tarde.

La regla cabe en una frase, y el libro oficial la trae como advertencia, no como sugerencia:

Do not rebase commits that exist outside your repository and that people may have based work on.

— Pro Git, 2.ª edición, «Git Branching — Rebasing»

Los comentarios de revisión anclados a SHAs concretos se despegan en el mismo movimiento — rebase un pull request abierto y el contexto de la revisión se evapora con los IDs viejos.

¿Cómo deshaces un rebase?

Los commits viejos sobreviven al rebase — el reflog es su escondite. El rebase mueve punteros de rama; no borra objetos. El rescate del banco, después de un reset --hard que tiró dos commits:

$ git reflog | head -4
1398836 HEAD@{0}: reset: moving to HEAD~2
67c0442 HEAD@{1}: merge feature: Fast-forward
1398836 HEAD@{2}: checkout: moving from feature to main
67c0442 HEAD@{3}: rebase (finish): returning to refs/heads/feature

$ git reset --hard HEAD@{1}
HEAD is now at 67c0442 c4 feature 2

Una línea, rama restaurada, trabajo staged y unstaged incluido. Las entradas del reflog caducan a los 90 días por defecto, así que el rescate tiene reloj — el mismo mecanismo de git undo last commit, y la decisión completa revert/reset vive en git revert vs reset.

verifica: git reflog | head -3 → la punta previa al rebase espera en HEAD@{1}, a un reset de distancia

¿Qué comando necesita tu situación?

La tabla es el post entero en seis filas — filtra por tu rama.

todas feature compartida local fork rescate
Situación Comando Por qué gana
Tu rama feature, nunca empujada git rebase main Historia lineal, una secuencia limpia para revisión
Una rama que otros bajan git merge Sin reescritura de SHAs — sin duplicados en ningún clone
main local divergido, nada empujado git pull --rebase Sincroniza sin nudo; tus commits quedan arriba
Fork alcanzando al upstream git merge upstream/main Cuadra con el flujo de fork sync; el PR queda enganchado
Hotfix que debe entrar ya git merge --no-ff Marcador visible de la entrada del fix, aun en una rama fast-forwardable
Un rebase que salió mal git reset --hard HEAD@{1} El reflog guarda la punta previa (~90 días)
¿Dónde encaja --squash?

git merge --squash toma los cambios de una rama y los deja en stage como un solo montón sin commit — sin commit de merge, sin vínculo con la historia de la rama. El autocompletado dice que «merge vs rebase vs squash» se busca a diario: squash es la tercera respuesta, para tirar una rama tras aterrizar su cambio neto. No reescribe nada; solo se niega a registrar los pasos internos de la rama.

¿Puede un equipo elegir solo uno?

Muchos lo hacen: rebase-para-lo-local, merge-hacia-lo-compartido es la política más común, y el botón merge de GitHub mantiene merge por defecto. Un «rebase para todo» también funciona — mientras ninguna rama compartida se reescriba jamás, la única frase que sobrevive a todos los debates de workflow.

La versión de diez segundos, una última vez: ¿el commit salió de tu máquina? No → rebase. Sí → merge. Cuando gana el equivocado de todas formas, el reflog tiene la salida — y el resto del mapa para deshacer vive en el hub git undo.

faq

— mrsaynothing

$ Compartir este artículo

$ Recibe el próximo how-to por email

Un email por post. Arréglalo y sigue.

self-hosted · sin terceros · baja con un clic

¿qué es esto?