Rebasar una confirmación de fusión de Git
Tomemos el siguiente caso:
Tengo algo de trabajo en una rama temática y ahora estoy listo para volver a fusionarme con el maestro:
* eb3b733 3 [master] [origin/master]
| * b62cae6 2 [topic]
|/
* 38abeae 1
Realizo la fusión desde master, resuelvo los conflictos y ahora tengo:
* 8101fe3 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
* | eb3b733 3 [origin/master]
|/
* 38abeae 1
Ahora, la fusión me llevó algo de tiempo, así que hago otra búsqueda y noto que la rama maestra remota tiene nuevos cambios:
* 8101fe3 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
| | * e7affba 4 [origin/master]
| |/
|/|
* | eb3b733 3
|/
* 38abeae 1
Si lo intento git rebase origin/master
desde el maestro, me veo obligado a resolver todos los conflictos nuevamente y también pierdo el compromiso de fusión:
* d4de423 2 [master]
* e7affba 4 [origin/master]
* eb3b733 3
| * b62cae6 2 [topic]
|/
* 38abeae 1
¿Existe una manera limpia de cambiar la base de la confirmación de fusión para terminar con un historial como el que muestro a continuación?
* 51984c7 Merge branch 'topic' [master]
|\
| * b62cae6 2 [topic]
* | e7affba 4 [origin/master]
* | eb3b733 3
|/
* 38abeae 1
Aquí hay dos opciones.
Una es hacer una rebase interactiva y editar la confirmación de fusión, rehacer la fusión manualmente y continuar con la rebase.
Otra es utilizar la --rebase-merges
opción on git rebase
, que se describe a continuación en el manual:
De forma predeterminada, una rebase simplemente eliminará las confirmaciones de fusión de la lista de tareas pendientes y colocará las confirmaciones rebasadas en una única rama lineal. Con --rebase-merges, la rebase intentará preservar la estructura de ramificación dentro de las confirmaciones que se van a rebasar, recreando las confirmaciones de fusión. Cualquier conflicto de fusión resuelto o modificación manual en estas confirmaciones de fusión deberá resolverse o volverse a aplicar manualmente. "
Ok, es una pregunta antigua y ya tiene una respuesta aceptada por @siride
, pero esa respuesta no fue suficiente en mi caso, ya que --preserve-merges
te obliga a resolver todos los conflictos por segunda vez. Mi solución se basa en la idea de @Tobi B
pero con comandos exactos paso a paso.
Comenzaremos en el mismo estado que se encuentra en la pregunta original:
* 8101fe3 Merge branch 'topic' [HEAD -> master]
|\
| * b62cae6 2 [topic]
| |
| | * f5a7ca8 5 [origin/master]
| | * e7affba 4
| |/
|/|
* | eb3b733 3
|/
* 38abeae 1
Tenga en cuenta que tenemos 2 confirmaciones por delante del maestro, por lo que la selección selectiva no funcionará.
Primero que nada, creemos el historial correcto:
git checkout -b correct-history # create new branch to save master for future git rebase --strategy=ours --preserve-merges origin/master
Usamos
--preserve-merges
para guardar nuestro compromiso de fusión en el historial. Solemos--strategy=ours
ignorar todos los conflictos de fusión, ya que no nos importa el contenido de esa confirmación fusionada, solo necesitamos un buen historial.La historia se verá así (ignorando al maestro):
* 51984c7 Merge branch 'topic' [HEAD -> correct-history] |\ | * b62cae6 2 [topic] * | f5a7ca8 5 [origin/master] * | e7affba 4 * | eb3b733 3 |/ * 38abeae 1
Consigamos el índice correcto ahora.
git checkout master # return to our master branch git merge origin/master # merge origin/master on top of our master
Es posible que obtengamos algunos conflictos de fusión adicionales aquí, pero solo serían conflictos de archivos modificados entre
8101fe3
yf5a7ca8
, no incluye conflictos ya resueltos detopic
El historial se verá así (ignorando el historial correcto):
* 94f1484 Merge branch 'origin/master' [HEAD -> master] |\ * | f5a7ca8 5 [origin/master] * | e7affba 4 | * 8101fe3 Merge branch 'topic' | |\ | | * b62cae6 2 [topic] |/ / * / eb3b733 3 |/ * 38abeae 1
La última etapa es combinar nuestra rama con el historial correcto y la rama con el índice correcto.
git reset --soft correct-history git commit --amend
Solemos
reset --soft
restablecer nuestra rama (y nuestro historial) al historial correcto, pero dejamos el índice y el árbol de trabajo como están. Luego usamoscommit --amend
para reescribir nuestra confirmación de fusión, que solía tener el índice incorrecto, con nuestro buen índice del maestro.Al final tendremos este estado (tenga en cuenta otra identificación del compromiso superior):
* 13e6d03 Merge branch 'topic' [HEAD -> master] |\ | * b62cae6 2 [topic] * | f5a7ca8 5 [origin/master] * | e7affba 4 * | eb3b733 3 |/ * 38abeae 1