¿Qué está haciendo realmente git cuando dice que está "resolviendo deltas"?

187

Durante el primer clon de un repositorio, git primero recibe los objetos (lo cual es bastante obvio), y luego pasa aproximadamente la misma cantidad de tiempo "resolviendo deltas". ¿Qué está pasando realmente durante esta fase del clon?

Nik Reiman
fuente
Relacionado: stackoverflow.com/questions/9478023/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
Ver también, para Git 2.20 (Q4 2018) y más islas delta: stackoverflow.com/a/52458712/6309
VonC

Respuestas:

54

Git usa la codificación delta para almacenar algunos de los objetos en paquetes. Sin embargo, usted no quiere tener que reproducir todos los cambios cada vez en un archivo determinado con el fin de obtener la versión actual, por lo Git también tiene instantáneas ocasionales de los contenidos de los archivos almacenados también. "Resolver deltas" es el paso que se ocupa de asegurarse de que todo se mantenga constante.

Aquí hay un capítulo de la sección "Git Internals" del libro Pro Git, que está disponible en línea, que habla sobre esto.

Ámbar
fuente
80
Esta respuesta es incorrecta. Parece describir cómo funciona Mercurial, no Git. Está surgiendo en las búsquedas de Google para este problema, así que siento la necesidad de responder. Git no almacena las diferencias entre confirmaciones como deltas; Git es una tienda de "objetos completos". Como tal, Git no necesita "instantáneas" para mostrar ningún archivo dado porque el historial de archivos no necesita ser reconstruido a partir de deltas. Así es como funciona Mercurial.
Nexus dice
12
El único lugar donde entra en juego la codificación delta es en el archivo del paquete, que es estrictamente para compresión y transferencia, no altera la forma en que Git "ve" el mundo. ( kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/… ) Consulte la respuesta de araqnid a continuación para obtener una respuesta precisa.
Nexus dice
44
Toda "instantánea" significa que en este contexto es una copia completa del estado de un archivo, en lugar de una versión codificada en delta. Como usted ha mencionado, Git hace uso de delta-codificación en packfiles. Nadie dijo que "altera la forma en que Git ve el mundo"; por favor deja de proyectar tus propios supuestos.
Ámbar
2
Tu respuesta aún es inexacta. "Git también tiene instantáneas ocasionales del contenido del archivo almacenado también". -- eso no es correcto. "'Resolver deltas' es el paso que se ocupa de garantizar que todo eso se mantenga constante". - eso tampoco es correcto, la respuesta de araqnid a continuación es correcta.
Nexus dice
1
Como se describe en el capítulo mencionado anteriormente, Git almacena siempre el contenido completo del archivo de la última versión. Las versiones anteriores se almacenan como archivos con código delta cuando son archivos "sueltos". Periódicamente (ya sea llamando git gco cuando Git lo determine necesario) Git comprimirá todos los archivos "sueltos" en un paquete para ahorrar espacio y se creará un archivo de índice en ese paquete. Por lo tanto, zlib se comprimirá con su propio algoritmo delta, pero Git usa la codificación delta para almacenar versiones anteriores. Dado que el acceso más común y frecuente es la última versión, que se almacena como una instantánea.
BrionS
118

Las etapas de git cloneson:

  1. Reciba un archivo "paquete" de todos los objetos en la base de datos de repositorio
  2. Crear un archivo de índice para el paquete recibido
  3. Echa un vistazo a la revisión de la cabeza (para un repositorio no descubierto, obviamente)

"Resolver deltas" es el mensaje que se muestra para la segunda etapa, indexando el archivo del paquete ("git index-pack").

Los archivos de paquete no tienen los ID de objeto reales en ellos, solo el contenido del objeto. Entonces, para determinar cuáles son las ID de objeto, git tiene que hacer una descompresión + SHA1 de cada objeto en el paquete para producir la ID de objeto, que luego se escribe en el archivo de índice.

Un objeto en un archivo de paquete puede almacenarse como un delta, es decir, una secuencia de cambios para realizar en otro objeto. En este caso, git necesita recuperar el objeto base, aplicar los comandos y SHA1 el resultado. El objeto base en sí podría tener que derivarse aplicando una secuencia de comandos delta. (Aunque en el caso de un clon, el objeto base ya se habrá encontrado, hay un límite para la cantidad de objetos fabricados que se almacenan en la memoria caché).

En resumen, la etapa de "resolución de deltas" implica la descompresión y suma de comprobación de la base de datos de repositorio completa, lo que no sorprende sorprendentemente, lleva mucho tiempo. Presumiblemente, descomprimir y calcular SHA1 en realidad lleva más tiempo que aplicar los comandos delta.

En el caso de una recuperación posterior, el archivo de paquete recibido puede contener referencias (como bases de objetos delta) a otros objetos que se espera que el git receptor ya tenga. En este caso, el git de recepción reescribe el archivo de paquete recibido para incluir dichos objetos referenciados, de modo que cualquier archivo de paquete almacenado sea ​​autosuficiente. Esto podría ser donde se originó el mensaje "resolviendo deltas".

araqnid
fuente
77
¿Puede esto ser paralelo?
brooksbp
¿Es esta compresión delta más que almacenar múltiples objetos en una secuencia de datos zlib?
fuz
1
@FUZxxl sí, está usando un algoritmo como diff o xdelta para comparar dos blobs y producir un script de edición
araqnid el
@brooksbp: solo con limitaciones. Debido a que el objeto con ID 103fa49 podría necesitar que se decodifique df85b51, pero cuando recibe 103fa49, df85b51 todavía no está allí (los archivos de paquete están estrictamente ordenados por hash sha1). Entonces, para todo lo que hace referencia solo a cosas que ya están allí, las cosas son fáciles, pero para todo lo demás, tendrá que esperar hasta que se reciba. Y esta compresión delta puede estar anidada, por lo que 103fa49 puede necesitar 4e9ba42 que a su vez necesita 29ad945 que a su vez necesita c9e645a ... se obtiene la imagen. [sí, noté que han pasado> 4 años;)]
Bodo Thiesen
2
@brooksbp: Resulta que estaba equivocado, el archivo del paquete NO necesita ser ordenado por hash sha1. Además, al escribir, git escribe los objetos necesarios antes que los objetos que los necesitan. Entonces, en realidad deberías poder paralelizarlo. Solo queda la desventaja: como no sabe qué objetos necesitará más adelante, tendrá que recrear algunos una y otra vez. Ver aquí: kernel.org/pub/software/scm/git/docs/technical/…
Bodo Thiesen
4

Amber parece estar describiendo el modelo de objetos que Mercurial o usos similares. Git no almacena los deltas entre versiones posteriores de un objeto, sino más bien instantáneas completas del objeto, cada vez. Luego comprime estas instantáneas usando la compresión delta, tratando de encontrar buenas deltas para usar, independientemente de en qué parte del historial existan.

Johan
fuente
55
En realidad, si bien Git puede almacenar objetos sueltos, no siempre se almacenan necesariamente como tales, ya que los objetos sueltos se pueden eliminar y reemplazar con contenido empaquetado. No creo que la respuesta de Amber haya dicho nada sobre versiones posteriores.
AlBlue