¿Cómo volver a fusionar una sucursal ya fusionada?

Tengo un gráfico de compromiso que se parece al siguiente. Los commits marcados con * representan muchos commits.

  A* | B--------- | | C* D* <- old feature branch | | E--------- | F* | G <- master 

La combinación E se realizó incorrectamente y algunos cambios (no todos) en C * se han perdido. ¿Cómo puedo rehacer esa fusión para reintroducir los cambios en el maestro actual?

Ya se ha empujado todo (proyecto de código abierto), por lo que cambiar el historial no es una opción.

Intenté crear un parche a partir de las confirmaciones C * y aplicarlo al maestro, pero debido a que algunos de los cambios de C * se han fusionado correctamente y debido a que el proyecto evolucionó desde esa confirmación, aproximadamente el 80% del parche falla.

Lo ideal sería tomar todos los cambios en C *, aplicarlos para dominar y resolver todos los conflictos. Pero debido a que las twigs ya se han fusionado, git no detecta ningún cambio y no permitirá que se fusionen nuevamente.

 $ git checkout 5bc5295 # C HEAD is now at 5bc5295... cleanup $ git checkout -b "missing-commits" Switched to a new branch 'missing-commits' $ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'. $ git merge missing-commits Already up-to-date. 

Lo ideal sería tomar todos los cambios en C *, aplicarlos para dominar y resolver todos los conflictos.

No, lo ideal sería rebobinar el time, hacer la fusión como lo era en ese momento (pero correctamente, esta vez), luego volver a aplicar los cambios F* y terminar con un master correcto.

Puedes hacerlo así:

 git checkout missing-commits git checkout -b correct-merge git merge D # do it right, this time around! git checkout master git checkout -b correct-master git rebase --onto correct-merge wrong-merge correct-master # have fun with the mother of all rebases! 

Si logra manejar todos los conflictos durante la rebase, terminará con exactamente lo que quería, originalmente, en la twig correct-master .

Como no quiere cambiar el historial, podría crear un gran parche y aplicarlo a su master actual, pero me gusta más este enfoque (suponiendo que haya hecho todo su trabajo en su directory de trabajo yourrepos ):

 cd yourrepos ; git checkout correct-master ; cd .. cp -a yourrepos newrepos rm -rf newrepos/.git cd yourrepos ; git checkout master ; cd .. cp -a yourrepos/.git newrepos/ 

Ahora, cuando ingresas a newrepos y haces un git status , estarás en newrepos master y verás precisamente todos los cambios entre master y correct-master , como si hubieras aplicado un parche. Capturará los files eliminados, los files nuevos, los files modificados, los permissions modificados, los enlaces simbólicos modificados, etc.

Idealmente, si todo salió bien, mostrará exactamente los commits perdidos de C Usa tu variante favorita de git add y finalmente un buen git commit (o varios, si lo prefieres), y listo. No se ha reescrito ningún historial.

Pruebe en lugar de crear parches simples y aplíquelos para usar git format-patch y git am . Esto debería darle la situación de estado de conflicto normal donde luego puede usar una herramienta de combinación para resolver los conflictos, a diferencia de git apply donde la aplicación simplemente falla.

Puedes probar con una selección de cerezas:

 git checkout master git cherry-pick B..[last_commit_of_C*] 

Git puede pedirle que confirme la selección, ya que los commits están en los antepasados.

Git almacena instantáneas y detecta los cambios sobre la marcha, por lo que la forma de trabajar con la diferencia entre una mala y una buena es registrar el bien como un descendiente de la mala, más o less lo mismo que cualquier otra cosa, pensándolo bien. Use git reset --soft para decirle a git el ancestro correcto:

 git checkout badmerge^1 # generate the right result git merge badmerge^2 git reset --soft badmerge # as an improvement on the wrong result git commit git checkout master # merge the difference now that git sees it git merge @{1} -m "applying corrections to a bad merge"