2012-05-01 12 views
28

Según this:¿git almacena información de diff en los objetos de commit?

Es importante tener en cuenta que esto es muy diferente de la mayoría de los sistemas SCM que es posible que esté familiarizado. Subversion, CVS, Perforce, Mercurial y similares todos usan sistemas de almacenamiento Delta; almacenan las diferencias entre una confirmación y la siguiente. Git no hace esto - almacena una instantánea de cómo se ven todos los archivos en su proyecto en esta estructura de árbol cada vez que se compromete. Este es un concepto muy importante de para entender cuando se usa Git.

Sin embargo, cuando corro git show $SHA1ofCommitObject ...

commit 4405aa474fff8247607d0bf599e054173da84113 
Author: Joe Smoe <[email protected]> 
Date: Tue May 1 08:48:21 2012 -0500 

    First commit 

diff --git a/index.html b/index.html 
new file mode 100644 
index 0000000..de8b69b 
--- /dev/null 
+++ b/index.html 
@@ -0,0 +1 @@ 
+<h1>Hello World!</h1> 
diff --git a/interests/chess.html b/interests/chess.html 
new file mode 100644 
index 0000000..e5be7dd 
--- /dev/null 
+++ b/interests/chess.html 
@@ -0,0 +1 @@ 
+Did you see on Slashdot that King's Gambit accepted is solved! <a href="http://game 

... que emite el diff del compromiso con las confirmaciones anteriores. Sé que git no almacena diffs en objetos blob, pero ¿almacena los diffs en objetos commit? ¿O es git show calculando dinámicamente la diferencia?

+7

Una nota al margen: Git en realidad comprime delta los objetos, pero es solo por el bien de la compresión. La gente a veces malinterpreta esto diciendo que las tiendas Git diffs. Hay alguna documentación del formato aquí: http://book.git-scm.com/7_the_packfile.html (Tenga en cuenta que los objetos que registra deltas entre son solo bloques de datos que descubrió que eran similares, no necesariamente versiones consecutivas del mismo archivo, aunque podrían serlo. Y, por supuesto, los deltas no son diffs línea por línea.) – Cascabel

+1

Actualizando el enlace muy relevante de Jefromi: http://git-scm.com/book/ es/Git-Internals-Packfiles –

Respuesta

32

No, los objetos de confirmación en git no contienen diffs; en su lugar, cada objeto de confirmación contiene un hash del árbol, que recursiva y completamente define el contenido del árbol fuente en esa confirmación. Hay un nice explanation in the git community book de lo que va dentro de los objetos blob, los objetos de árbol y los objetos de confirmación.

Todas las diferencias que le muestran las herramientas de git se calculan a petición del contenido completo de los archivos.

52

Lo que la declaración significa es que, la mayoría de los otros sistemas de control de versiones necesitan un punto de referencia en el pasado para poder volver a crear la confirmación actual.

Por ejemplo, en algún momento en el pasado, un VCS basados ​​en diff (sistema de control de versiones) habría almacenado una instantánea completa:

x = snapshot 
+ = diff 
History: 
x-----+-----+-----+-----(+) Where we are now 

Así, en un escenario de este tipo, para volver a crear la state at (now), tendría que verificar (x) y luego aplicar diffs para cada uno (+) hasta llegar al ahora. Tenga en cuenta que sería extremadamente ineficaz almacenar los deltas para siempre, por lo que de vez en cuando, los VCS basados ​​en delta almacenan una instantánea completa. Here's how its done for subversion.

Ahora, git es diferente. Git almacena referencias para completar blobs y esto significa que con git, , solo una confirmación es suficiente para volver a crear la base de código en ese momento. Git no necesita buscar información de revisiones anteriores para crear una instantánea.

Entonces, si ese es el caso, ¿dónde entra la compresión delta que usa git?

Bueno, no es más que un concepto de compresión: no tiene sentido almacenar la misma información dos veces, si solo una pequeña cantidad ha cambiado. Por lo tanto, represente lo que ha cambiado, pero almacene una referencia a él, de modo que la confirmación a la que pertenece, que en realidad es un árbol de referencias, pueda volver a crearse sin tener en cuenta las confirmaciones pasadas. Sin embargo, la cuestión es que Git no hace esto inmediatamente después de cada confirmación, sino más bien en una ejecución de recolección de basura. Por lo tanto, si git no ha ejecutado su recolección de elementos no utilizados, puede ver objetos en su índice con contenido muy similar.

Sin embargo, cuando Git ejecuta su recolección de basura (o cuando llama al git gc manualmente), los duplicados se limpian y se crea un archivo de paquete de solo lectura.No tiene que preocuparse por ejecutar la recolección de basura manualmente - git contiene heurística que le indica cuándo hacerlo.

+4

Sorprendido por los pocos votos. –

+0

Gracias, Carl. Entonces, comprometer pequeños cambios en un gran proyecto no infla el repositorio con muchas copias redundantes (al menos a largo plazo). – shuhalo

+0

@shuhalo Eso es correcto, aunque es incluso mejor que eso. Si hizo una copia de todos sus archivos fuente y los agregó a su confirmación actual, la única información adicional después de una ejecución de gc serían los metadatos: nombres de archivos, rutas, autor y demás. El contenido real de los archivos simplemente se referiría a los blobs en el pasado que provienen del código original. – Carl