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

499

¿Cuál es la diferencia entre git mergey git rebase?

Daniel Peñalba
fuente
14
desde que mi respuesta fue eliminada, visite este enlace para obtener la respuesta correcta para esta pregunta: git-scm.com/book/en/Git-Branching-Rebasing#The-Basic-Rebase
HiB
66
Por cierto, agregaré este sitio. Todo lo que necesitas saber sobre git learn jugando: pcottle.github.io/learnGitBranching
Rollyng
Lea esto primero: git-scm.com/book/en/v2/… Luego: git-scm.com/book/en/v2/Git-Branching-Rebasing Realmente lo comprenderá.
Liber

Respuestas:

867

Supongamos que originalmente había 3 confirmaciones, A, B, C:

A B C

Luego, el desarrollador Dan creó commit Dy el desarrollador Ed creó commit E:

A B C D E

Obviamente, este conflicto debe resolverse de alguna manera. Para esto, hay 2 formas:

MERGE :

ABCDEM

Ambos commits Dy Etodavía están aquí, pero creamos commit de fusión Mque hereda los cambios de ambos Dy E. Sin embargo, esto crea forma de diamante , lo que muchas personas encuentran muy confuso.

REBASE :

ABCDER

Creamos commit R, cuyo contenido de archivo real es idéntico al de merge commit Manterior. Pero, nos deshacemos de commit E, como si nunca hubiera existido (denotado por puntos - línea de fuga). Debido a esta eliminación, Edebe ser local para el desarrollador Ed y nunca debería haberse enviado a ningún otro repositorio. La ventaja de rebase es que se evita la forma del diamante , y la historia se mantiene en línea recta, ¡a la mayoría de los desarrolladores les encanta eso!

mvp
fuente
53
Bonitas ilustraciones. Sin embargo, no estoy totalmente de acuerdo con el tono positivo de que se maneje el rebase. Tanto en la fusión como en el rebase pueden ocurrir conflictos que requieren resolución manual. Y como siempre cuando los programadores están involucrados, existe una posibilidad no descuidada de errores, también conocidos como errores. Si ocurre un error de fusión, todo el equipo o la comunidad pueden ver la fusión y verificar si se introdujo un error allí. La historia del rebase permanece en el repositorio de 1 desarrollador e incluso allí solo tiene una vida limitada en el reflog. Puede verse mejor, pero nadie más puede ver tan fácilmente lo que salió mal.
Uwe Geuder el
> "Sin embargo, esto crea forma de diamante, lo que muchas personas encuentran muy confuso". Um ... ¿puedes dar más detalles?
Greg Maletic el
@GregMaletic: la forma del diamante es una historia no lineal. No sé sobre ti, pero no me gustan las cosas no lineales en general. Dicho esto, puedes usar la combinación con diamantes si realmente lo prefieres, nadie te obliga.
mvp
1
Si bien esta respuesta es extremadamente útil, sería mejor si agregara comandos git reales con archivos foo.txt simples para reproducirlos localmente. Como dijo el último usuario, no es obvio quién está haciendo rebase.
Vórtice
1
@pferrel: No creo que lo hayas entendido correctamente. git mergeno intercala confirmaciones (pero podría aparecer así al mirar git log). En cambio, git mergemantiene ambas historias de desarrollo de Dan y Ed conservadas intactas, como se vio desde cada punto de vista a la vez. git rebasehace que parezca que Dan trabajó en ello primero, y Ed lo siguió. En ambos casos (fusión y rebase), el árbol de archivos resultante real es absolutamente idéntico.
mvp
158

Realmente me encanta este extracto de 10 cosas que odio de git (da una breve explicación de rebase en su segundo ejemplo):

3. Documentación cutre

Las páginas del manual son un todopoderoso "f *** you" 1 . Describen los comandos desde la perspectiva de un informático, no de un usuario. Caso en punto:

git-push – Update remote refs along with associated objects

Aquí hay una descripción para humanos:

git-push – Upload changes from your local repository into a remote repository

Actualización, otro ejemplo: (gracias cgd)

git-rebase – Forward-port local commits to the updated upstream head

Traducción:

git-rebase – Sequentially regenerate a series of commits so they can be 
             applied directly to the head node

Y luego tenemos

git-merge - Join two or more development histories together

Que es una buena descripción.


1. sin censura en el original

mvw
fuente
El problema no es el lenguaje o si el usuario es un informático o no. Si bien volver a redactarlo de otra manera ayuda a aclarar los fines (es decir, lo que sucede), falla al explicar los medios (cómo sucede). Git requiere comprender los medios para comprender los fines. Es precisamente comprender los medios lo que hace que Git sea tan difícil. Como herramienta, algo usado para simplificar o reducir el esfuerzo requerido en la tarea, Git falla horriblemente. Lamentablemente, demasiados desarrolladores no se dan cuenta.
ATL_DEV
128

Personalmente, no me parece muy útil la técnica de diagramación estándar: las flechas siempre parecen apuntarme en la dirección incorrecta. (Generalmente apuntan hacia el "padre" de cada commit, lo que termina siendo hacia atrás en el tiempo, lo cual es extraño).

Para explicarlo en palabras:

  • Cuando rebasas tu rama en su rama, le dices a Git que haga que parezca su rama limpiamente, luego hiciste todo tu trabajo a partir de allí. Eso hace un paquete de cambios limpio y conceptualmente simple que alguien puede revisar. Puede repetir este proceso nuevamente cuando haya nuevos cambios en su rama, y ​​siempre terminará con un conjunto limpio de cambios "en la punta" de su rama.
  • Cuando fusionas su rama en tu rama, unes las dos historias de ramas en este punto. Si vuelve a hacer esto más tarde con más cambios, comenzará a crear un hilo intercalado de historias: algunos de sus cambios, algunos de mis cambios, algunos de sus cambios. Algunas personas encuentran esto desordenado o indeseable.

Por razones que no entiendo, las herramientas GUI para Git nunca han hecho un gran esfuerzo para presentar historias de fusión de manera más limpia, abstrayendo las fusiones individuales. Entonces, si quieres un "historial limpio", debes usar rebase.

Me parece recordar haber leído publicaciones de blog de programadores que solo usan rebase y otros que nunca usan rebase.

Ejemplo

Trataré de explicar esto con un ejemplo de solo palabras. Digamos que otras personas en su proyecto están trabajando en la interfaz de usuario y usted está escribiendo documentación. Sin rebase, su historial podría verse así:

Write tutorial
Merge remote-tracking branch 'origin/master' into fixdocs
Bigger buttons
Drop down list
Extend README
Merge remote-tracking branch 'origin/master' into fixdocs
Make window larger
Fix a mistake in howto.md

Es decir, fusiones y confirmaciones de IU en medio de sus confirmaciones de documentación.

Si vuelve a crear el código en el maestro en lugar de fusionarlo, se vería así:

Write tutorial
Extend README
Fix a mistake in howto.md
Bigger buttons
Drop down list
Make window larger

Todos sus commits están en la parte superior (más nuevos), seguidos por el resto del master rama.

( Descargo de responsabilidad: soy el autor de la publicación "10 cosas que odio de Git" mencionada en otra respuesta )

Steve Bennett
fuente
42

Si bien la respuesta aceptada y más votada es excelente, también me parece útil tratar de explicar la diferencia solo con palabras:

unir

  • “Está bien, tenemos dos estados desarrollados de manera diferente en nuestro repositorio. Fusionémoslos juntos. Dos padres, un hijo resultante ".

rebase

  • "Dar los cambios de la rama principal (cualquiera que sea su nombre) a mi rama característica. Hágalo fingiendo que mi trabajo principal comenzó más tarde, de hecho, en el estado actual de la rama principal ".
  • "Reescribe la historia de mis cambios para reflejar eso". (necesita forzarlos, porque normalmente el control de versiones consiste en no alterar el historial dado)
  • "Probablemente, si los cambios que realicé tienen poco que ver con mi trabajo, la historia en realidad no cambiará mucho, si miro mis confirmaciones diff por diff (también puede pensar en 'parches')".

resumen: cuando es posible, el rebase es casi siempre mejor. Facilitar la reintegración en la rama principal.

¿Porque? ➝ su trabajo de características se puede presentar como un gran 'archivo de parche' (también conocido como diff) con respecto a la rama principal, sin tener que 'explicar' varios padres: al menos dos, provenientes de una fusión, pero probablemente muchos más, si hay Hubo varias fusiones. A diferencia de las fusiones, los rebases múltiples no suman. (otra gran ventaja)

Frank Nocke
fuente
18

Git rebase está más cerca de una fusión. La diferencia en rebase es:

  • los commits locales se eliminan temporalmente de la rama.
  • ejecuta el git pull
  • inserte nuevamente todos sus commits locales.

Eso significa que todas sus confirmaciones locales se trasladan al final, después de todas las confirmaciones remotas. Si tiene un conflicto de fusión, también debe resolverlo.

Willem Franco
fuente
7

Para facilitar la comprensión puede ver mi figura.

Rebase cambiará el hash de confirmación, de modo que si desea evitar gran parte del conflicto, simplemente use rebase cuando esa rama esté completa / completa.

ingrese la descripción de la imagen aquí

Nhan Cao
fuente
0

Encontré un artículo realmente interesante sobre git rebase vs merge , pensé en compartirlo aquí

  • Si desea ver el historial completamente igual a como sucedió, debe usar merge. La fusión conserva la historia, mientras que rebase la reescribe.
  • La fusión agrega una nueva confirmación a su historial
  • Rebasar es mejor para simplificar un historial complejo, puede cambiar el historial de confirmación mediante un rebase interactivo.
nagendra547
fuente