How-to git backport (rebase / cherry-pick) una twig ya fusionada

En nuestro process de Git, "maestro" es la twig de integración para twigs de temas y arreglos para el ciclo de publicación actual, pero también mantenemos una twig "estable" donde tenemos que respaldar cuidadosamente algunas de nuestras soluciones ya probadas con éxito en el maestro.

Toda la dificultad es que la twig ya se ha fusionado en "master" (de lo contrario, es muy fácil con rebase –onto)

  • No queremos cambiar el process de la otra manera porque a) no queremos arreglar todo en la twig "estable", yb) a veces tenemos que hacer algunos cambios en la twig "estable" que no hacemos Quiero unirme en "maestro".
  • Claramente, no podemos fusionar la corrección en la twig "estable" porque esto respaldará muchas características no deseadas.

Gráfico de la situación inicial que describo:

I--J (stable) / / / - A - B - C - D - E - F - G (master) \ / X -- Y (fix/123) 

Gráfico del tipo de situación que queremos alcanzar:

  I--J (stable) / \ / X'- Y' (fix/123-stable) / - A - B - C - D - E - F - G (master) \ / X -- Y (fix/123) 

Casos más complejos son posibles, como fusión múltiple para completar una solución:

 - A - B - C - D - E - F - G - H (master) \ / / X - Y ----- Z (fix/123) 

Pero no permitimos fusionarnos en una twig de reparación, por lo que nunca tendremos algo como esto:

 - A - B - C - D - E - F - G (master) \ \ / X - Y - Z (fix/123) 

Para lograr esto, podemos seleccionar cuidadosamente o volver a establecer la base de la twig de reparación:

1) cherry-pick (típicamente, ¿cómo puedo respaldar un commit en git? ):

 git checkout -b fix/123-stable stable git cherry-pick XY 

Esto parece fácil, pero no lo es cuando se trata de ejemplos de la vida real; ¡siempre existe el riesgo de olvidar algunas confirmaciones o de elegir las incorrectas!

2) rebase –onto ( https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html ):

2.a) el path "no funciona":

 git rebase --onto stable master fix/123 

¡Esto no hace nada ya que Fix / 123 ya se ha fusionado para dominar! 2.b) la manera "no mucho mejor que la selección":

 git rebase --onto stable D fix/123 

Esto todavía es un poco arriesgado porque necesita tomar el SHA de D (y NO X, por ejemplo).

2.c) la forma "utilizar una reference de inicio temporal":

 git tag begin D git rebase --onto stable begin fix/123 git tag -d begin 

Esto mejora la situación anterior, ya que la label hace que sea más fácil hacerlo o visualizarla en una herramienta gráfica, pero todavía es mucho trabajo manual.

3.d) el "reinicio del maestro duro antes de la fusión" (al primer punto de ramificación) Hum, parece difícil de describir y de hacer.

Entonces, lo que estoy buscando es una forma portátil de git (no bash / grep / cut / sed implícita);

1) enumera todas las confirmaciones hechas en una twig ya fusionada de nuevo en "maestro" (aquí X e Y, y también Z en el caso de "fusión múltiple") para seleccionarlas fácilmente

2) get la confirmación del primer punto de sucursal de una sucursal ya fusionada de nuevo en "maestro"

2.a) esto no se puede hacer con el command "git merge-base" porque la fusión ya está hecha (incluso varias veces)

2.b) He encontrado aquí Encontrar un punto de ramificación con Git? el siguiente command bash pellizqué un poco:

 git rev-list --boundary --date-order --reverse fix/123..master | grep -m 1 - | cut -c2- 

pero el suyo no es un command fácil ni portátil (es decir, no funciona sin las herramientas Bash o Cygwin)

Soy bastante nuevo para Git, así que disculpe cualquier malentendido que haya podido tener en su situación.

Usando este fragment de código:

 diff -u <(git rev-list --first-parent fix/123) <(git rev-list --first-parent master) | sed -ne 's/^ //p' | head -1 

De esta respuesta: @lindes responde a "¿Encontrar un punto de ramificación con Git?"

Si tienes un tree como este:

Árbol Inicial

Entonces, el resultado del command anterior con some-fix en lugar de fix/123 será:

f1efa4a9c029281a22d4fa8dd6607c523e7191f5

¿Cuál es la confirmación en la que se creó su bifurcación de arreglo inicial?

A continuación, puede ejecutar una merge-base rápida para determinar dónde termina una some-fix :

 $ git merge-base master some-fix 1b9ebb7157a958e9adc3b8eda9bf4175cd821c4b 

Y luego, utilizando una selección de cereza del range de revisión, puede get esos cambios en:

 $ git cherry-pick f1efa4a..1b9ebb7 

Y terminas con:

Árbol final

Que contiene las confirmaciones adicionales de la twig de reparación inicial. Desea realizar el checkout -b adicional checkout -b para crear su bifurcación de fix/123-stable , en lugar de simplemente virar en stable , pero el método debería ser el mismo.

Tenga en count también que la respuesta a la que hice reference menciona la installation de ese largo y tedioso command diff como un alias llamado oldest-ancestor , que debería ahorrarle mucho time.

Para que quede constancia, aquí están las dos soluciones que finalmente estoy usando en base a la respuesta de Craig Otis que apunta a la respuesta de lindes sobre "Encontrar un punto de ramificación con Git" , usando Bash alias el file ".gitconfig" (probado bajo Linux Ubuntu 12.10)

Estado inicial, donde la twig "fix / 123" ya se ha fusionado de nuevo en "master" :

  I--J (stable) / - A - B - C - D - E - F - G (master) \ / X - Y (fix/123) 

1) Para volver a establecer la base de la twig "corregir / 123" que comienza desde "maestro" a "estable" (esta es una respuesta genérica para la mayoría de las personas que leen esto):

Agregue los siguientes alias de Bash en su file ".gitconfig":

 [alias] oldest-ancestor = !bash -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' - rebase-onto = !bash -c 'git rebase --onto $1 `git oldest-ancestor $2 $3` $3' - 

Luego usa la línea de command:

 git rebase-onto stable master fix/123 

Y aquí estás:

  I--J (stable) / \ / X'- Y' (fix/123) / - A - B - C - D - E - F - G (master) \ / X - Y 

2) Para volver a establecer la base de la twig "fix / 123" comenzando desde "master", creando una nueva twig "fix / 123-stable" en "estable" (esta es la respuesta más específica que voy a usar).

Agregue los siguientes alias de Bash en su file ".gitconfig":

 [alias] oldest-ancestor = !bash -c 'diff -u <(git rev-list --first-parent "${1:-master}") <(git rev-list --first-parent "${2:-HEAD}") | sed -ne \"s/^ //p\" | head -1' - rebase-onto = !bash -c 'git branch $4 $2 && git rebase --onto $3 `git oldest-ancestor $1 $4` $4' - 

Luego usa la línea de command:

 git rebase-onto master fix/123 stable fix/123-stable 

Y aquí estás:

  I--J (stable) / \ / X'- Y' (fix/123-stable) / - A - B - C - D - E - F - G (master) \ / X - Y (fix/123)