Diferencia entre merge y rebase en Git

Ni rebase ni merge en pull por sí solos “borran” tus trabajos — en ambos casos, tus commits permanecen en el repositorio (en la historia de la rama o como SHAs antiguos mientras el reflog esté activo).

  • pull.rebase false (merge): git pull creará un commit de merge, tus commits y los de otros no se reescriben, la historia de la rama simplemente se une con la rama. Visualmente es más seguro para la mente: puedes ver claramente las líneas que se unen.
  • pull.rebase true (rebase): tus commits locales se copian encima de los remotos (nuevos hashes). El contenido de los commits suele ser el mismo, pero los “viejos” commits después de un rebase exitoso pueden quedar solo en el git reflog — esto es normal, desde allí se pueden restaurar (git reset --hard hacia el ref deseado del reflog) si algo sale mal.

Si lo principal es “no perder trabajos”:

  1. Antes de pasos arriesgados — haz un commit (o git stash) y, si lo deseas, una rama separada (git branch backup-tgisn-46) — una copia del puntero, un respaldo económico.
  2. No confundir con pérdidas de comandos como git reset --hard, force push sin necesidad, git clean -fd.
  3. Después de rebase/merge, no ejecutar git gc agresivamente durante varios días — el reflog guarda un punto de retorno.

Práctico para “no perder, no complicar mucho la historia”: git config pull.rebase false — al haber divergencias, siempre obtendrás un merge, sin reescribir tus commits locales. Si ya te ha gustado el enfoque de rebase (como en el antiguo pull --rebase) — puedes dejar pull.rebase true, simplemente no push --force en ramas compartidas sin acuerdo previo.

En resumen: no se pierden trabajos por la estrategia elegida en pull; el riesgo está en otras comandos y en force push; para tranquilidad — commit + rama de respaldo antes de operaciones inciertas.

Aquí la misma situación que tenías: un commit común C, después en origin cinco commits r1…r5, en local — uno L (mi trabajo).

1. Antes de pull (divergidos)

gitGraph
  commit id: "C (común)"
  branch local
  checkout local
  commit id: "L (mi commit)"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"

Significado: el extremo de local = L, el extremo de main = r5, ancestro común = C. Esto no se pierde en ambos casos — solo cambia cómo se une la historia.


2. Después de git pull sin rebase (pull.rebase falsemerge)

gitGraph
  commit id: "C"
  branch local
  checkout local
  commit id: "L"
  checkout main
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  checkout local
  merge main
  commit id: "M (commit de merge)"

Aparece un commit de merge M con dos padres (L y r5). Los commits L y r1…r5 como objetos permanecen; la historia es ramificada, sin reescrituras.


3. Después de git pull con rebase (pull.rebase truerebase)

gitGraph
  commit id: "C"
  commit id: "r1"
  commit id: "r2"
  commit id: "r3"
  commit id: "r4"
  commit id: "r5"
  commit id: "L′ (mismo parche, nuevo hash)"

La historia es lineal: tu trabajo está encima de los remotos. El commit L en la historia tiene un nuevo commit L′ (mismo parche respecto a r5, hash diferente); el viejo L sigue visible en el git reflog mientras no elimines reflog expire.


En resumen: merge — rama bifurcada + nodo de merge; rebase — línea única, tu commit “rejugado” encima. Los trabajos en sentido de cambios en archivos no se pierden en ambos escenarios normales; solo difiere la forma de la historia y los hashes del commit local en el rebase.