¿Por qué este git rebase piensa que no hay nada que hacer?

En este ejemplo, git no cree que sea necesario volver a establecer la base, pero claramente lo hace.

Aquí hay un script rápido para crear un mini repository git de testing

#!/bin/bash rm -rf testgit mkdir testgit cd testgit git init echo -e "a\nb\nc" > file git add file git commit -am 'first' git checkout -b lineA echo -e "A\nb\nc" > file git commit -am 'A' git checkout -b lineB echo -e "a\nB\nc" > file git commit -am 'B' git checkout -b lineC echo -e "a\nb\nC" > file git commit -am 'C' 

Después de que esto se ejecuta, aquí está el file en cada twig

 master | lineA | lineB | lineC ------------------------------ a A aa bb B b ccc C 

Ahora fusionemos todas las twigs en master, después de lo cual cada letra del file debe estar en mayúscula

 $ git checkout master $ git merge lineA 

Bueno.

 $ git checkout lineB $ git rebase master Current branch lineB is up to date. 

¿Qué? No, el maestro cambió.

 $ git checkout master $ cat file A b c $ git checkout lineB $ cat file a B c 

Me parece que la línea de ramificación B necesita volver a basarse para incorporar el cambio al maestro realizado mediante la fusión de la línea A.

¿Por qué Git no piensa que esto debe hacerse?

Además, si haces esto

 $ git checkout master $ git merge lineA Already up-to-date. $ git merge lineB ... 1 file changed, 2 insertions(+), 2 deletions(-) $ cat file a B c $ git merge lineC ... 1 file changed, 2 insertions(+), 2 deletions(-) $ cat file a b C 

Aquí las fusiones deberían entrar en conflicto, pero git las está castigando silenciosamente. No sé si esto es relevante, pero parece extraño.

Resultado de los primeros commands

Después del script que tenemos (abreviatura de los nombres de las twigs de línea …):

 master lA lB lC ↓ ↓ ↓ ↓ first----A----B----C 

Estos commands:

 $ git checkout master $ git merge lineA 

da como resultado una fusión de avance rápido, que solo mueve al master para apuntar a la misma confirmación como línea lineA

Dando:

  master lA lB lC ↓ ↓ ↓ first----A----B----C 

Sin trabajo para la Rebase

Entonces esta secuencia de commands:

 $ git checkout lineB $ git rebase master 

está diciendo mover la twig lineB sobre el master .

… pero ya está encima de master .

master debería tener algunos commits en su historial que lineB no tenga para que el command rebase tenga trabajo por hacer.

Sin Conflicto de Fusión

Cuando Git crea un commit de fusión, considera el historial de los padres que están entrando en la fusión. En este caso, ambas twigs apuntan a confirmaciones en una cadena común de confirmaciones. Git puede ver que la confirmación A llegó antes de la confirmación B que vino antes de la confirmación C Como tal, Git considera que los últimos compromisos se sumn a las confirmaciones anteriores y, como tales, no entran en conflicto.

Si, en cambio, tuvieras un historial como:

  master ↓ ---A / | lB | ↓ first----B 

entonces Git los vería como líneas paralelas de desarrollo. En ese caso, fusionar lB en master o viceversa entraría en conflicto. Esto se debe a que B no es una adición sobre A en el historial y, como tal, Git necesita información del usuario para comprender cuál de los cambios conservar.

Creo que tu punto de confusión está más atrás. Cuando ejecutaste

 git commit -am 'first' git checkout -b lineA 

lineA una nueva twig llamada lineA pero el punto de bifurcación fue la confirmación que acabas de hacer (" first "). Como dice Git, first es parte de la historia de ambas twigs, y en ese punto en tu script también es la confirmación más reciente en ambas twigs. El logging de Git con algunas opciones muestra que ambos nombres de twig apuntan a la primera confirmación, que en este ejemplo es la identificación de confirmación 58b7dcf:

 git log --graph --oneline --decorate * 58b7dcf (HEAD, master, lineA) first 

Continuo:

 echo -e "A\nb\nc" > file git commit -am 'A' git log --graph --oneline --decorate * ed40ed2 (HEAD, lineA) A * 58b7dcf (master) first 

El command de logging muestra que el compromiso A (ed40ed2) es ahora el compromiso más reciente en la lineA , y su compromiso principal es el first , que sigue siendo la confirmación más reciente en el master . Si fuera a fusionar lineA nuevo a master en este momento, sería una fusión de avance rápido (trivial), porque no se realizaron confirmaciones para master ya que lineA bifurcó de él. Del mismo modo, lineA en master no haría nada excepto informar

 Current branch lineA is up to date. 

porque la confirmación más reciente en el master sucursal (la punta de la sucursal maestra) sigue siendo parte del historial de la línea de sucursal lineA Continuo:

 git checkout -b lineB echo -e "a\nB\nc" > file git commit -am 'B' git checkout -b lineC echo -e "a\nb\nC" > file git commit -am 'C' git log --graph --oneline --decorate * 4033067 (HEAD, lineC) C * f742aed (lineB) B * ed40ed2 (lineA) A * 58b7dcf (master) first 

Cada nueva sucursal se basa en la confirmación más reciente de la anterior, sin desarrollo paralelo. Continuo:

 git checkout master git merge lineA Updating 58b7dcf..ed40ed2 Fast-forward 

Observe que se trata de una fusión de avance rápido, por lo que lo único que hizo fue mover master a ed40ed2:

 git log --graph --oneline --decorate * ed40ed2 (HEAD, master, lineA) A * 58b7dcf first 

Finalmente:

 git checkout lineB git rebase master Current branch lineB is up to date. git log --graph --oneline --decorate * f742aed (HEAD, lineB) B * ed40ed2 (master, lineA) A * 58b7dcf first 

Tu escribiste:

¿Qué? No, el maestro cambió.

Sí, el master cambió, pero no de una manera que afectara el historial de lineB o lineC . master avanzó rápidamente para confirmar ed40ed2, que ya era el padre de lineB . Para ser precisos, es el padre de f742aed, que es la identificación de confirmación que obtuve para la confirmación B

La confusión, para las personas acostumbradas a otros sistemas de control de versiones, es que Git registra una estructura de datos tipo tree (técnicamente un DAG) para los loggings de compromiso, no los nombres de las twigs. Las twigs son efímeras; solo son tags, como tags de versiones mobilees. Las relaciones padre-hijo entre las confirmaciones es lo que se ve en el git log --graph y otras herramientas de visualización.