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)
pull
: aceptar --rebase-merges
para recrear la topología de la rama
Similar al preserve
modo que simplemente pasa la --preserve-merges
opción al rebase
comando, el merges
modo simplemente pasa la
--rebase-merges
opción.
Esto permitirá a los usuarios reabastecer convenientemente las topologías de confirmación no triviales al extraer nuevas confirmaciones, sin aplanarlas.
git rebase
La página de manual ahora tiene una sección completa dedicada al cambio de la historia con fusiones .
Extraer:
Existen razones legítimas por las que un desarrollador puede querer recrear confirmaciones de fusión: para mantener la estructura de la rama (o "topología de confirmación") cuando se trabaja en múltiples ramas interrelacionadas.
En el siguiente ejemplo, el desarrollador trabaja en una rama de tema que refactoriza la forma en que se definen los botones, y en otra rama de tema que usa esa refactorización para implementar un botón "Informar un error".
La salida de git log --graph --format=%s -5
puede verse así:
* Merge branch 'report-a-bug'
|\
| * Add the feedback button
* | Merge branch 'refactor-button'
|\ \
| |/
| * Use the Button class for all buttons
| * Extract a generic Button class from the DownloadButton one
Es posible que el desarrollador quiera volver a basar esas confirmaciones en una nueva master
mientras mantiene la topología de la rama, por ejemplo, cuando se espera que la primera rama del tema se integre master
mucho antes que la segunda, por ejemplo, para resolver conflictos de fusión con cambios en la
DownloadButton
clase que hizo en master
.
Este rebase se puede realizar usando la --rebase-merges
opción
Ver commit 1644c73 para un pequeño ejemplo:
rebase-helper
--make-script
: introduce una bandera para volver a combinar las fusiones
El secuenciador acaba de aprender nuevos comandos destinados a recrear la estructura de la rama ( similar en espíritu a --preserve-merges
, pero con un diseño sustancialmente menos roto ).
Permitamos rebase--helper
que genere listas de tareas haciendo uso de estos comandos, activados por la nueva --rebase-merges
opción.
Para una topología de confirmación como esta (donde HEAD apunta a C):
- A - B - C (HEAD)
\ /
D
la lista de tareas generada se vería así:
# branch D
pick 0123 A
label branch-point
pick 1234 D
label D
reset branch-point
pick 2345 B
merge -C 3456 D # C
¿Cuál es la diferencia con --preserve-merge
?
Commit 8f6aed7 explica:
Érase una vez, este desarrollador aquí pensó: ¿no sería bueno si, por ejemplo, los parches de Git para Windows en la parte superior del núcleo Git pudieran representarse como un matorral de ramas y volverse a basar en la parte superior del núcleo de Git para ¿Mantener un conjunto de series de parches que se pueden elegir fácilmente?
El original intento de responder a esta era: git rebase --preserve-merges
.
Sin embargo, ese experimento nunca tuvo la intención de ser una opción interactiva, y solo fue respaldado git rebase --interactive
porque la implementación de ese comando ya parecía muy, muy familiar: fue diseñada por la misma persona que diseñó --preserve-merges
: la suya verdaderamente.
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.
Algún tiempo después, otro desarrollador (¡te estoy mirando, Andreas! ;-)) decidió que sería una buena idea permitir --preserve-merges
que se combinara --interactive
(¡con advertencias!) Y el mantenedor de Git (bueno, el mantenedor de Git interino durante la ausencia de Junio, eso es) de acuerdo, y fue entonces cuando el glamour del --preserve-merges
diseño comenzó a desmoronarse bastante rápido y sin glamour.
Aquí Jonathan está hablando de Andreas Schwab de Suse.
Puedes ver algunas de sus discusiones en 2012 .
¿La razón? En el --preserve-merges
modo, los padres de una confirmación de fusión (o, para el caso, de cualquier confirmación) no se indicaron explícitamente, sino que estaban
implícitos en el nombre de confirmación pasado al pick
comando .
Esto hizo imposible, por ejemplo, reordenar los commits .
Por no hablar de mover confirmaciones entre ramas o, Dios no lo quiera, dividir ramas temáticas en dos.
Lamentablemente, estas deficiencias también impidieron que ese modo (cuyo propósito original era servir las necesidades de Git para Windows, con la esperanza adicional de que también podría ser útil para otros) sirviera las necesidades de Git para Windows.
Cinco años más tarde, cuando se volvió realmente insostenible tener una serie de parches hodge-podge grandes y poco manejables de parches en parte relacionados y en parte no relacionados en Git para Windows que de vez en cuando se basaban en las etiquetas centrales de Git (ganando la ira inmerecida del desarrollador de la git-remote-hg
serie desafortunada
que primero dejó obsoleto el enfoque competitivo de Git para Windows, solo para ser abandonado sin mantenedor más tarde) fue realmente insostenible, nacieron las " tijeras de jardín Git " : un guión, que se apoya en la parte superior del rebase interactivo, eso determinaría primero la topología de ramificación de los parches que se volverán a crear, creará una lista de pseudo tareas para su posterior edición, transformará el resultado en una lista de tareas real (haciendo un uso intensivo deexec
comando para "implementar" los comandos de la lista de tareas que faltan) y finalmente recrear la serie de parches en la parte superior del nuevo compromiso base.
(El script de tijeras de jardín Git se menciona en este parche en commit 9055e40 )
Eso fue en 2013.
Y tomó alrededor de tres semanas elaborar el diseño e implementarlo como un script fuera de árbol. Huelga decir que la implementación necesitó bastantes años para estabilizarse, mientras que el diseño en sí demostró ser sólido.
Con este parche, la bondad de las tijeras de jardín Git trata de la git
rebase -i
misma .
Pasar la --rebase-merges
opción generará una lista de tareas que se puede entender fácilmente y donde es obvio cómo reordenar las confirmaciones .
Se pueden introducir nuevas ramas insertando label
comandos y llamando merge <label>
.
Y una vez que este modo se haya estabilizado y aceptado universalmente, podemos desaprobar el error de diseño que fue--preserve-merges
.
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)
rebase --exec
: haz que funcione con --rebase-merges
La idea de --exec
es agregar una exec
llamada después de cada uno pick
.
Desde la introducción del fixup!
/ s quash!
commit, esta idea se extendió a aplicarse a "pick, posiblemente seguida de una corrección / cadena calabaza", es decir, un exec no se inserta entre una pick
y cualquiera de sus correspondientes
fixup
o squash
líneas.
La implementación actual utiliza un truco sucio para lograrlo: se supone que solo hay comandos pick / fixup / squash, y luego
inserta las exec
líneas antes que cualquier otra que pick
no sea la primera, y agrega una final.
Con las listas de tareas generadas por git rebase --rebase-merges
, esta implementación simple muestra sus problemas: produce exactamente lo incorrecto cuando hay label
, reset
y merge
comandos.
Cambiemos la implementación para hacer exactamente lo que queremos: buscar
pick
líneas, omitir cualquier cadena de arreglo / aplastar, y luego insertar la exec
línea . Enjabonar, enjuagar, repetir.
Nota: nos esforzamos por insertar antes de las líneas de comentarios siempre que sea posible, ya que las confirmaciones vacías están representadas por líneas de selección comentadas (y queremos insertar una línea ejecutiva de una selección anterior antes de dicha línea, no después).
Mientras lo hace, también agregue exec
líneas después de los merge
comandos, porque son similares en espíritu a los pick
comandos: agregan nuevos commits.
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)
Asegúrese de que las referencias / reescritas / sean por árbol de trabajo
a9be29c (secuenciador: crea referencias generadas por el label
comando worktree-local, 2018-04-25, Git 2.19) agrega refs/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.
- add_per_worktree_entries_to_dir()
se actualiza para asegurarse de que el listado de referencia mire por árbol de trabajo en refs/rewritten/
lugar de uno por repositorio.
common_list[]
se actualiza para que git_path()
devuelva la ubicación correcta. Esto incluye " rev-parse --git-path
".
Este desastre es creado por mí.
Comencé a tratar de arreglarlo con la introducción de refs/worktree,
dónde todas las referencias serán por árbol de trabajo sin tratamientos especiales.
Las referencias desafortunadas / reescritas llegaron antes que las referencias / worktree, así que esto es todo lo que podemos hacer.
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)
path.c
: no llame a la match
función sin valor entrie_find()
Firmado por: SZEDER Gábor
'logs / refs' no es una ruta de trabajo específica del árbol, pero desde commit b9317d55a3 (Asegúrese de que refs / rewritten / is per-worktree, 2019-03-07, v2.22.0-rc0) ' git rev-parse --git-path
' ha estado devolviendo una ruta falsa si hay un final ' /
' presente:
$ git -C WT/ rev-parse --git-path logs/refs --git-path logs/refs/
/home/szeder/src/git/.git/logs/refs
/home/szeder/src/git/.git/worktrees/WT/logs/refs/
Usamos una trie
estructura de datos para decidir de manera eficiente si una ruta pertenece al directorio común o está trabajando en un árbol específico.
Como sucede, b9317d55a3 desencadenó un error que es tan antiguo como la trie
implementación en sí, agregado en 4e09cf2acf (" path
: optimizar la comprobación de directorio común", 2015-08-31, Git v2.7.0-rc0 - fusión incluida en el lote # 2 ).
De acuerdo con el comentario que describe trie_find()
, solo debería llamar a la función de coincidencia dada 'fn' para un "/ -o- \ 0-terminado prefijo de la clave para la cual el trie contiene un valor".
Esto no es cierto: hay tres lugares donde trie_find () llama a la función de coincidencia, pero a uno de ellos le falta la verificación de la existencia del valor.
b9317d55a3 agregó dos nuevas claves a trie
:
- '
logs/refs/rewritten
' y
- '
logs/refs/worktree
', junto al ya existente ' logs/refs/bisect
'.
Esto dio como resultado un trie
nodo con la ruta ' logs/refs/
', que no existía antes y que no tiene un valor asociado.
Una consulta para ' logs/refs/
' encuentra este nodo y luego toca ese sitio de llamada de la match
función que no verifica la existencia del valor y, por lo tanto, invoca la match
función con un NULL
valor.
Cuando la match
función check_common()
se invoca con un NULL
valor, devuelve 0, lo que indica que la ruta consultada no pertenece al directorio común, lo que finalmente resulta en la ruta falsa que se muestra arriba.
Agregue la condición que falta para trie_find()
que nunca invoque la función de coincidencia con un valor no existente.
check_common()
entonces ya no tendrá que verificar que obtuvo un valor no NULL, por lo tanto, elimine esa condición.
Creo que no hay otros caminos que puedan causar una salida falsa similar.
AFAICT la única otra tecla que resulta en que la función de coincidencia se llame con un NULL
valor es ' co
' (debido a las teclas ' common
' y ' config
').
Sin embargo, como no están en un directorio que pertenece al directorio común, se espera la ruta de trabajo específica resultante del árbol.
git --rebase-merges
última instancia, reemplazará a la anteriorgit --preserve-merges
. Vea mi respuesta a continuación