Subtree de rebase de Git

Supongamos que tengo el siguiente escenario:

o (master) / o--o (WIP1) / / o--o--o--o--o--o (WIP2) (X) \ o--o (WIP3) 

¿Hay un command git que crea una nueva twig para que contenga el subtree después de la twig X? Quiero realizar una "gran rebase", quiero que las tres twigs WIP se vuelvan a establecer en el maestro.

Sé que puedo hacerlo con algunos scripts de Bash, pero me gustaría saber cómo hacerlo con un command git.

No hay un solo command de git para eso. Tendrás que hacer un trabajo manual. En tu situación:

  o (master) / o--o (WIP1) / / X--o--o--B--o--o (WIP2) \ o--o (WIP3) 

Primero rebase WIP1 en master:

 git rebase --onto master X WIP1 

que conducirá a esto:

  o--o (WIP1) (master) / o--o--o--B' / / X--o--o--B--o--o (WIP2) \ o--o (WIP3) 

Si ahora ejecuta git rebase --onto master X WIP2 , obtiene esta estructura:

  o--o (WIP1) (master) / o--o--o--B' / \ / o--o--B''--o--o (WIP2) / X--o--o--B--o--o (WIP3) 

Probablemente esto no sea lo que quieres, así que ahora debes volver a establecer la base de WIP2 y WIP3 en B' :

 git rebase --onto B' B WIP2 git rebase --onto B' B WIP3 

que conducirá a esto:

  o--o (WIP1) (master) / o--X--o--o--B'--o--o (WIP2) \ o--o (WIP3) 
  o (master) / o--o (WIP1) / / o--p--p--o--o--o (WIP2) (X) (Y) \ o--o (WIP3) 

Esto debería ser un rebase --onto (puede ver un ejemplo en " Cómo mover ciertos commits a otra twig en git? "):

  git rebase --onto master X WIP1 git rebase --onto master X WIP2 git rebase --onto master X WIP3 

De la testing de Chronial , eso daría:

  p'--p'--o--o (WIP2) / o-----o-----p--p--o--o--o (WIP1) (X) (master) (Y') \ p''--p''--o--o (WIP3) 

Entonces la primera rebase está bien, pero necesitas get Y SHA, y:

  git rebase --onto Y' Y WIP2 git rebase --onto Y' Y WIP3 

He marcado esta pregunta como duplicada. Escribiré lo que expliqué con la otra respuesta pero usando tu ejemplo.

El enfoque que uso para estos casos de uso es fusionar todas las twigs para moverlas a un nodo artificial común , y luego usar el command rebase con la opción --preserve-merges . La fusión de todas las twigs expondrá 1 punto final que se utilizará como parámetro de input final para rebase --onto . El punto de inicio suele ser obvio, el origen del subtree para moverse.

Al fusionarse para get el punto final del subtree , los conflictos deberían evitarse explícitamente. Por lo tanto, los commands de fusión deben ser instruidos para resolverlos automáticamente con la opción -Xours . El resultado de la fusión no es importante ya que estos nodos de fusión artificial se descartarán después de la rebase.

Se recomienda crear un nuevo package de ramificación para no perder las references originales. En el ejemplo anterior, se realizarían los siguientes commands:

 $ git checkout -b pack WIP1 # create new branch at 'WIP1' $ git merge -s recursive -Xours WIP2 # merges WIP2 into pack (node p2) $ git merge -s recursive -Xours WIP3 # merges WIP3 into pack 

A continuación se puede ver en qué se convertiría el tree. Se han creado dos nuevos nodos artificiales p2 y package con las fusiones.

  o (master) / / (WIP1) (p2) / o-----o-----o----o (pack) / / / / o--o--o--o-----o-----o / (WIP2) (X) \ / o------------o (WIP3) 

Ahora es el momento de volver a establecer la base. Como ahora hay un punto final común para todas las twigs ( package ), es fácil mover todo el subtree con:

 $ git rebase --preserve-merges --onto master X pack 

Que produce esto:

  (WIP1') (p2') o-----o-----o----o (pack') (master) / / / o----o----o--o--o-----o-----o / (WIP2') (X) \ / o------------o (WIP3') 

Ahora es el momento de reorganizar las references. No sé por qué, en algunos casos las references se trasladan y en otros no. Escriba esto para cada reference WIP1, WIP2, WIP3 o lo que necesite:

 $ git checkout WIP1 $ git reset --hard <WIP1' hash> 

Y, finalmente, deshágase de las confirmaciones artificiales que se crearon para generar un nodo final de subtree común.

 $ git branch -D pack $ git branch -D p2 # if there is any 

Entonces el tree final sería:

  (WIP1') o-----o (master) / o----o----o--o--o-----o-----o (WIP2') (X) \ o------------o (WIP3') 

Si quieres tener este resultado

  o (oldmaster)--o--o--B--o--o(WIP1)--o--o(WIP2)--o--o(WIP3)(master) / / X 

Usted debe hacer esto:

 git rebase --onto master X WIP1 /* move WIP1 on master */ git rebase --onto WIP1 WIP2~3 WIP2 /* move WIP2 on WIP1 */ git rebase --onto WIP2 WIP3~3 WIP3 /* move WIP3 on WIP2 */ git reset --hard WIP3 /* move master index to WIP3 */