La documentaciónrebase
de Git para el comando es bastante breve:
--preserve-merges
Instead of ignoring merges, try to recreate them.
This uses the --interactive machinery internally, but combining it
with the --interactive option explicitly is generally not a good idea
unless you know what you are doing (see BUGS below).
Entonces, ¿qué sucede realmente cuando lo usas --preserve-merges
? ¿Cómo difiere del comportamiento predeterminado (sin esa bandera)? ¿Qué significa "recrear" una fusión, etc.
git
git-rebase
Chris
fuente
fuente
git --rebase-merges
última instancia, reemplazará a la anteriorgit --preserve-merges
. Vea mi respuesta a continuaciónRespuestas:
Al igual que con un rebase git normal, git with
--preserve-merges
primero identifica una lista de confirmaciones realizadas en una parte del gráfico de confirmaciones y luego reproduce esas confirmaciones encima de otra parte. Las diferencias con--preserve-merges
preocupación sobre qué commits se seleccionan para la reproducción y cómo funciona esa reproducción para los commits de fusión.Para ser más explícito acerca de las principales diferencias entre rebase normal y preservación de fusión:
git checkout <desired first parent>
), mientras que el rebase normal no tiene que preocuparse por eso.Primero trataré de describir "suficientemente exactamente" lo que
--preserve-merges
hace rebase , y luego habrá algunos ejemplos. Por supuesto, uno puede comenzar con los ejemplos, si eso parece más útil.El algoritmo en "breve"
Si realmente quiere meterse en la maleza, descargue la fuente git y explore el archivo
git-rebase--interactive.sh
. (Rebase no es parte del núcleo C de Git, sino que está escrito en bash. Y, detrás de escena, comparte código con "rebase interactivo").Pero aquí esbozaré lo que creo que es su esencia. Para reducir la cantidad de cosas en las que pensar, me he tomado algunas libertades. (p. ej., no trato de capturar con un 100% de precisión el orden preciso en el que tienen lugar los cálculos e ignorar algunos temas que parecen menos centrales, p. ej., qué hacer con los commits que ya se han seleccionado entre las ramas).
Primero, tenga en cuenta que un rebase que no conserva la fusión es bastante simple. Es más o menos:
Rebase
--preserve-merges
es comparativamente complicado. Aquí es tan simple como pude hacerlo sin perder cosas que parecen bastante importantes:Rebase con un
--onto C
argumento debería ser muy similar. En lugar de comenzar la reproducción de confirmación en la CABEZA de B, comienza la reproducción de confirmación en la CABEZA de C. (Y use C_new en lugar de B_new).Ejemplo 1
Por ejemplo, tome commit graph
m es un compromiso de fusión con los padres E y G.
Supongamos que reajustamos el tema (H) en la parte superior del maestro (C) usando un rebase normal que no conserva la fusión. (Por ejemplo, tema de pago; maestro de rebase ). En ese caso, git seleccionaría las siguientes confirmaciones para la reproducción:
y luego actualice el gráfico de confirmación de la siguiente manera:
(D 'es el equivalente repetido de D, etc.)
Tenga en cuenta que merge commit m no está seleccionado para la reproducción.
Si, en su lugar,
--preserve-merges
realizamos un rebase de H sobre C. (por ejemplo, tema de pago; rebase --preserve-merges master ). En este nuevo caso, git seleccionaría los siguientes commits para la repetición:Ahora m fue elegido para la repetición. También tenga en cuenta que los padres de fusión E y G fueron seleccionados para su inclusión antes de la fusión de compromiso m.
Aquí está el gráfico de confirmación resultante:
Nuevamente, D 'es una versión escogida (es decir, recreada) de D. Igual para E', etc. Se ha reproducido cada commit que no está en master. Tanto E como G (los padres combinados de m) se han recreado como E 'y G' para servir como los padres de m '(después de la rebase, la historia del árbol sigue siendo la misma).
Ejemplo 2
A diferencia del rebase normal, el rebase que conserva la fusión puede crear varios hijos del encabezado aguas arriba.
Por ejemplo, considere:
Si volvemos a basar H (tema) encima de C (maestro), entonces los commits elegidos para rebase son:
Y el resultado es así:
Ejemplo 3
En los ejemplos anteriores, tanto el commit de fusión como sus dos padres son commits repetidos, en lugar de los padres originales que tiene el commit de fusión original. Sin embargo, en otros rebases, un commit de fusión reproducido puede terminar con padres que ya estaban en el gráfico de commit antes de la fusión.
Por ejemplo, considere:
Si volvemos a basar el tema en maestro (preservando las fusiones), entonces los compromisos de repetición serán
El gráfico de confirmación reescrito se verá así:
Aquí, el comando fusionar m 'repetido' obtiene los padres que ya existían en el gráfico de compromiso, es decir, D (la CABEZA del maestro) y E (uno de los padres del comité de fusión original m).
Ejemplo 4
La rebase de preservación de fusión puede confundirse en ciertos casos de "confirmación vacía". Al menos esto es cierto solo en algunas versiones anteriores de git (por ejemplo, 1.7.8.)
Tome este gráfico de compromiso:
Tenga en cuenta que ambos commit m1 y m2 deberían haber incorporado todos los cambios de B y F.
Si intentamos hacer
git rebase --preserve-merges
de H (tema) en D (maestro), se eligen las siguientes confirmaciones para la reproducción:Tenga en cuenta que los cambios (B, F) unidos en m1 ya deberían estar incorporados en D. (Esos cambios ya deberían estar incorporados en m2, porque m2 combina los elementos secundarios de B y F.) Por lo tanto, conceptualmente, reproducir m1 encima de D probablemente debería ser un no-op o crear un commit vacío (es decir, uno donde la diferencia entre revisiones sucesivas está vacía).
En cambio, sin embargo, git puede rechazar el intento de reproducir m1 encima de D. Puede obtener un error así:
Parece que uno olvidó pasar una bandera a git, pero el problema subyacente es que a git no le gusta crear commits vacíos.
fuente
git rebase --preserve-merges
es mucho más lento que unrebase
sin--preserve-merges
. ¿Es eso un efecto secundario de encontrar los compromisos correctos? ¿Hay algo que uno pueda hacer para acelerarlo? (Por cierto ... ¡gracias por la respuesta muy detallada!)Git 2.18 (Q2 2018) mejorará considerablemente la
--preserve-merge
opción al agregar una nueva opción."
git rebase
" aprendido "--rebase-merges
" para trasplantar toda la topología del gráfico de compromiso en otro lugar .(Nota: Git 2.22, Q2 2019, en realidad se desvaloriza
--preserve-merge
, y Git 2.25, Q1 2020, deja de anunciarlo en el "git rebase --help
" resultado )Ver cometer 25cff9f , cometer 7543f6f , cometer 1131ec9 , cometer 7ccdf65 , cometer 537e7d6 , cometer a9be29c , cometer 8f6aed7 , cometer 1644c73 , cometer d1e8b01 , cometer 4c68e7d , cometer 9055e40 , cometer cb5206e , cometer a01c2a5 , cometer 2f6b1d1 , cometer bf5c057 (25 abr 2018) por Johannes Schindelin (
dscho
) .Ver commit f431d73 (25 abr 2018) por Stefan Beller (
stefanbeller
) .Ver commit 2429335 (25 de abril de 2018) por Phillip Wood (
phillipwood
) .(Fusionada por Junio C Hamano -
gitster
- en commit 2c18e6a , 23 de mayo de 2018)git rebase
La página de manual ahora tiene una sección completa dedicada al cambio de la historia con fusiones .Extraer:
Ver commit 1644c73 para un pequeño ejemplo:
¿Cuál es la diferencia con
--preserve-merge
?Commit 8f6aed7 explica:
Y por "el suyo verdaderamente", el autor se refiere a sí mismo: Johannes Schindelin (
dscho
) , quien es la razón principal (con algunos otros héroes - Hannes, Steffen, Sebastian, ...) de que tenemos Git para Windows (aunque atrás en el día - 2009 - eso no fue fácil ).Está trabajando en Microsoft desde septiembre de 2015 , lo que tiene sentido teniendo en cuenta que Microsoft ahora usa mucho Git y necesita sus servicios.
Esa tendencia comenzó en 2013 en realidad, con TFS . Desde entonces, Microsoft administra el repositorio de Git más grande del planeta . Y, desde octubre de 2018, Microsoft adquirió GitHub .
Puedes ver a Johannes hablar en este video para Git Merge 2018 en abril de 2018.
Aquí Jonathan está hablando de Andreas Schwab de Suse.
Puedes ver algunas de sus discusiones en 2012 .
(El script de tijeras de jardín Git se menciona en este parche en commit 9055e40 )
Git 2.19 (Q3 2018) mejora la nueva
--rebase-merges
opción al hacer que funcione--exec
.La "
--exec
" opción de "git rebase --rebase-merges
" colocó los comandos exec en lugares incorrectos, lo que se ha corregido.Ver commit 1ace63b (09 de agosto de 2018), y commit f0880f7 (06 de agosto de 2018) por Johannes Schindelin (
dscho
) .(Fusionada por Junio C Hamano -
gitster
- en commit 750eb11 , 20 de agosto de 2018)Git 2.22 (Q2 2019) corrige el uso de las referencias / reescritura / jerarquía para almacenar un estado intermedio de rebase, que inherentemente hace que la jerarquía por árbol de trabajo.
Ver commit b9317d5 , commit 90d31ff , commit 09e6564 (07 mar 2019) por Nguyễn Thái Ngọc Duy (
pclouds
) .(Fusionada por Junio C Hamano -
gitster
- en commit 917f2cd , 09 abr 2019)a9be29c (secuenciador: crea referencias generadas por el
label
comando worktree-local, 2018-04-25, Git 2.19) agregarefs/rewritten/
como espacio de referencia por árbol de trabajo.Desafortunadamente (lo malo) hay un par de lugares que necesitan actualización para asegurarse de que realmente sea por árbol de trabajo.
Con Git 2.24 (cuarto trimestre de 2019), "
git rebase --rebase-merges
" aprendió a manejar diferentes estrategias de fusión y pasarles opciones específicas de estrategia.Ver commit 476998d (04 Sep 2019) por Elijah Newren (
newren
) .Ver cometer e1fac53 , comprometerse a63f990 , comprometerse 5dcdd74 , comprometerse e145d99 , comprometerse 4e6023b , comprometerse f67336d , comprometerse a9c7107 , comprometerse b8c6f24 , comprometerse d51b771 , comprometerse c248d32 , comprometerse 8c1e240 , comprometerse 5efed0e , comprometerse 68b54f6 , comprometerse 2e7bbac , comprometerse 6180b20 , comprometerse d5b581f (31 Jul 2019) porJohannes Schindelin (
dscho
) .(Fusionada por Junio C Hamano -
gitster
- en commit 917a319 , 18 sep 2019)Con Git 2.25 (Q1 2020), la lógica utilizada para diferenciar las referencias globales del repositorio local y del repositorio es fija, para facilitar la fusión-preservación.
Ver commit f45f88b , commit c72fc40 , commit 8a64881 , commit 7cb8c92 , commit e536b1f (21 oct 2019) por SZEDER Gábor (
szeder
) .(Fusionada por Junio C Hamano -
gitster
- en commit db806d7 , 10 nov 2019)fuente
--preserve-merges
realidad no "preserva" las fusiones como quieras, es muy ingenuo. Esto le permite preservar los compromisos de fusión y sus relaciones de compromiso principal al tiempo que le brinda la flexibilidad de un rebase interactivo. Esta nueva característica es increíble y si no fuera por esta respuesta SO bien escrita, ¡no lo habría sabido!