Git se fusiona después de git rebase?

Estaba leyendo este artículo http://supercollider.github.io/development/git-cheat-sheet.html , que propuso el siguiente flujo de trabajo:

git checkout master git pull --rebase # update local from remote git rebase master chgs git checkout master git merge chgs git push 

Estoy seguro de que no entiendo cómo funciona esto y por qué es útil.

La tercera línea, git rebase master somechanges , pone commits desde chgs después del último commit desde master pero sin fusionarlos, y deja HEAD apuntando al último commit desde chgs , así:

 (master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k)<--HEAD 

¿ chgs me deja con chgs ? ¿Es por eso que necesito echar un vistazo al master otra vez?

¿Y por qué tenemos que fusionar los cambios en maestro? ¿Eso no hace un gráfico como este?

 (master-commit-n-1)<--(master-commit-n)<--(chgs-commit-k-1)<--(chgs-commit-k) \.(master-with-merged-chgs-commit-k)<--HEAD 

No veo por qué la horquilla superior es útil.

En order:

La tercera línea, git rebase master somechanges , pone commits desde chgs después del último commit desde master pero sin fusionarlos …

Sí, asumiendo que algunos somechanges es un error tipográfico para chgs (la página referenceda usa aún más deletreos).

y deja HEAD apuntando a la última confirmación de chgs

Sí, pero solo de manera indirecta: HEAD literalmente contiene ref: refs/heads/chgs , es decir, te quedan check-out de branch chgs . Es chgs sí que apunta a la última confirmación.

¿ chgs me deja con chgs ?

Sí.

Específicamente, la "twig actual", la que se imprime como on branch ... cuando se usa el git status , es simplemente lo que sea refs/heads/ branch en el file HEAD , cuando HEAD contiene refs: refs/heads/ branch . Al ejecutar la git checkout branch primero se asegura de que esté bien actualizar el tree de trabajo, luego lo hace y lo pone en esa twig, al volver a escribir HEAD .

Internamente, la git rebase upstream branch invoca la git rebase upstream branch git checkout branch , por lo que todo el process comienza git rebase upstream branch en la sucursal.

¿Y por qué tenemos que fusionar los cambios en maestro? ¿Eso no hace un gráfico como [recortado]?

Necesita 1 la merge para mover la label.

Prefiero dibujar el gráfico de compromiso con letras, o a veces solo con pequeños o nodos, con guiones únicos o flechas cortas entre ellos para indicar las relaciones de crianza. Y, robando (pero modificando) una hoja de git log --graph --oneline --decorate , agrego el nombre de la twig a la derecha con una flecha más larga. Si HEAD nombra la twig, agrego HEAD= al frente.

Lo que tienes justo después de la rebase se puede dibujar así:

 ... - E - F <-- master \ G - H - I <-- HEAD=chgs 

Aquí la confirmación labelda F es la punta del master de twig, por lo que el master apunta a F (y F apunta a E y así sucesivamente). La punta de las ramificaciones chgs es commit I ; I señalo a H ; H señala a G ; y G apunta a F Y, por supuesto HEAD=chgs entonces estás en esa twig.

Una vez que hayas finalizado la tarea de git checkout master , actualizará tu tree de trabajo como siempre, y hará que HEAD apunte al punto master que apunta a F Entonces, si ejecuta git merge chgs , git busca para ver si es posible hacer una fusión de "avance rápido":

 ... - E - F <-- HEAD=master \ G - H - I <-- chgs 

Una fusión de avance rápido es posible cuando la confirmación actual ( F , en este caso) ya es un ancestro de la confirmación objective ( I ). Si es así, la label de bifurcación se quita de la confirmación actual y simplemente se pega en la confirmación de destino:

 ... - E - F \ G - H - I <-- chgs, HEAD=master 

(Ya no existe ninguna razón de arte ASCII para mantener el pliegue en el dibujo [de F hacia abajo y hacia la derecha a G ], pero lo mantuve para la simetría visual).

Como Cupcake notó en su respuesta más rápida , puedes forzar una fusión real con --no-ff . Dibujaría esto como:

 ... - E - F ------------- M <-- HEAD=master \ / G - H - I <-- chgs 

En cualquier caso (avance rápido, o "fusión real"), una vez hecho esto, puede eliminar de manera segura las tags de twig chgs , ya que todas sus confirmaciones son chgs comenzando en el master y trabajando hacia atrás (a lo largo de ambas twigs si "combinación real"). O bien, puede conservarlo y agregarle más compromisos, si lo prefiere.

Una nota interesante aquí es que, en este caso particular, el tree de trabajo resultante asociado con el compromiso M es exactamente el mismo que el del compromiso I La diferencia key es que esto crea una confirmación de fusión real (una confirmación con múltiples padres). El primer elemento primario es cualquier confirmación que haya estado en la twig anterior, en este caso, confirme F y las confirmaciones restantes (solo la confirmación I , aquí) son las twigs fusionadas.

(Puedes anular esto-el tree de trabajo es el mismo, quiero decir-con aún más banderas de fusión, pero en este caso no querrás. Ese tipo de cosas, anulando el tree de trabajo, está destinado principalmente para "matar" fuera de "una sucursal conservando la historia: una especie de post de" mira, probamos esto y no funcionó "para que alguien mire el código el año que viene).


1 O no es necesario, si no desea mover las tags. Sin embargo, si tiene la intención de devolverle su trabajo a alguien, o dejar que lo pull de usted, mirarán sus tags. Es bueno para ellos si organizas tus tags muy bien para ellos. Pero siempre depende de ti.

# 1

La tercera línea, git rebase master somechanges , pone commits desde chgs después del último commit desde master pero sin fusionarlos, y deja HEAD apuntando al último commit desde chgs , como este:

 (master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) <- HEAD 

El efecto de chgs en master es equivalente a fusionar master en chgs , porque el estado de tu código en la última confirmación será equivalente al estado después de una merge .

# 2

¿ chgs me deja con chgs ? ¿Es por eso que necesito echar un vistazo al master otra vez?

Sí.

# 3

¿Y por qué tenemos que fusionar los cambios en maestro? ¿Eso no hace un gráfico como este?

 (master-n-1) <- (master-n) <- (chgs-k-1) <- (chgs-k) \ (master-with-merged-chgs-k) <- HEAD 

No. Debido a que chgs encima de master , git reconocerá que el último commit en chgs representa efectivamente el estado del master "+" chgs , por lo que simplemente "avanza rápidamente" la twig master a la punta de chgs sin hacer una merge commit:

 (n-1) <- (n) <- (k-1) <- (k) <- HEAD/master/chgs 

Si quisieras obligar a Git a hacer un commit de fusión en su lugar, podrías pasar el indicador --no-ff para merge :

 git merge --no-ff chgs # Results in this (n-1) <- (n) <- (k-1) <- (k) <- chgs \ \ --------------(merge) <- HEAD/master 

# 4

No veo por qué la horquilla superior es útil.

Es útil para actualizar twigs de características con cambios en sentido ascendente desde el master , sin crear un set de confirmaciones de fusión networkingundantes en la twig de características. El resultado final es que su historial de desarrollo se vuelve más simple y fácil de trabajar, en lugar de contener un montón de confusiones de fusión adicionales que realmente no necesita, y que simplemente hacen que la historia sea más complicada y más difícil de manipular.

A continuación, se explica con más detalle qué hace cada uno de estos commands.

GIT Checkout Master

Cambia a la twig master .

Supongamos que localmente tenemos esto (donde * indica la twig actual):

 M1 -- M2 = master* \__ C1 = chgs 

git pull –rebase

Actualiza la twig master local desde la twig remota, reestableciendo cualquier cambio local que se haya realizado en la twig master para que venga después de los cambios remotos.

Supongamos que esto nos da un nuevo cambio de M3:

 M1 -- M2 -- M3 = master* \__ C1 = chgs 

git rebase master chgs

Rebases cambia de la twig chgs local para que sigan desde la twig master local (pero permanezcan en su propia twig). También cambia a la twig de chgs .

 M1 -- M2 -- M3 = master \__ C1' = chgs* 

GIT Checkout Master

Vuelve a la twig master .

 M1 -- M2 -- M3 = master* \__ C1' = chgs 

git merge chgs

chgs con el master .

 M1 -- M2 -- M3 ------- M4 = master* \__ C1' __/ = chgs 

git push

Impulsa estos cambios al origen.