Supongamos que originalmente había 3 confirmaciones, A, B, C:
Luego, el desarrollador Dan creó commit Dy el desarrollador Ed creó commit E:
Obviamente, este conflicto debe resolverse de alguna manera. Para esto, hay 2 formas:
MERGE :
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 :
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!
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
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 )
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)
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.
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.
Respuestas:
Supongamos que originalmente había 3 confirmaciones,
A
,B
,C
:Luego, el desarrollador Dan creó commit
D
y el desarrollador Ed creó commitE
:Obviamente, este conflicto debe resolverse de alguna manera. Para esto, hay 2 formas:
MERGE :
Ambos commits
D
yE
todavía están aquí, pero creamos commit de fusiónM
que hereda los cambios de ambosD
yE
. Sin embargo, esto crea forma de diamante , lo que muchas personas encuentran muy confuso.REBASE :
Creamos commit
R
, cuyo contenido de archivo real es idéntico al de merge commitM
anterior. Pero, nos deshacemos de commitE
, como si nunca hubiera existido (denotado por puntos - línea de fuga). Debido a esta eliminación,E
debe 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!fuente
git merge
no intercala confirmaciones (pero podría aparecer así al mirargit log
). En cambio,git merge
mantiene ambas historias de desarrollo de Dan y Ed conservadas intactas, como se vio desde cada punto de vista a la vez.git rebase
hace 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.Realmente me encanta este extracto de 10 cosas que odio de git (da una breve explicación de rebase en su segundo ejemplo):
Y luego tenemos
Que es una buena descripción.
1. sin censura en el original
fuente
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:
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í:
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í:
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 )
fuente
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
rebase
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)
fuente
Git rebase está más cerca de una fusión. La diferencia en rebase es:
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.
fuente
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.
fuente
Encontré un artículo realmente interesante sobre git rebase vs merge , pensé en compartirlo aquí
fuente