¿Qué contiene el índice git EXACTAMENTE?

178

¿Qué contiene exactamente el índice Git y qué comando puedo usar para ver el contenido del índice?


Actualizar

Gracias por todas sus respuestas. Sé que el índice actúa como un área de ensayo, y lo que está comprometido está en el índice en lugar del árbol de trabajo. Tengo curiosidad por saber en qué consiste un objeto índice. Supongo que podría ser una lista de nombre de archivo / nombre de directorio, pares SHA-1, ¿una especie de árbol virtual tal vez?

¿Existe, en la terminología de Git, algún comando de plomería que pueda usar para enumerar el contenido del índice?

mochidino
fuente
3
deberías leer y ver diagramas - muy útil: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix
1
@kernix el dominio ha expirado. Ya no es muy útil.
narendra-choudhary

Respuestas:

162

El libro de Git contiene un artículo sobre lo que incluye un índice :

El índice es un archivo binario (generalmente guardado .git/index) que contiene una lista ordenada de nombres de ruta, cada uno con permisos y el SHA1 de un objeto blob; git ls-filespuede mostrarle el contenido del índice:

$ git ls-files --stage
100644 63c918c667fa005ff12ad89437f2fdc80926e21c 0   .gitignore
100644 5529b198e8d14decbe4ad99db3f7fb632de0439d 0   .mailmap

El problema de Racy git da más detalles sobre esa estructura:

El índice es una de las estructuras de datos más importantes en git.
Representa un estado de árbol de trabajo virtual mediante el registro de la lista de rutas y sus nombres de objeto y sirve como un área de ensayo para escribir el siguiente objeto de árbol que se confirmará.
El estado es "virtual" en el sentido de que no necesariamente tiene que coincidir, y a menudo no coincide, con los archivos del árbol de trabajo.


Para ver más, cf. " git / git / Documentation / technical / index-format.txt ":

El archivo de índice de Git tiene el siguiente formato

Todos los números binarios están en orden de bytes de red.
La versión 2 se describe aquí a menos que se indique lo contrario.

  • Un encabezado de 12 bytes que consta de:
    • Firma de 4 bytes :
      la firma es {' D', ' I', ' R', ' C'} (significa " dircache")
    • Número de versión de 4 bytes :
      las versiones compatibles actuales son 2, 3 y 4.
    • Número de entradas de índice de 32 bits.
  • Una serie de entradas de índice ordenadas .
  • Extensiones : las
    extensiones se identifican por firma.
    Las extensiones opcionales pueden ignorarse si Git no las comprende.
    Git actualmente admite árbol en caché y resuelve extensiones de deshacer.
    • Firma de extensión de 4 bytes. Si el primer byte es ' A' .. ' Z', la extensión es opcional y puede ignorarse.
    • Tamaño de 32 bits de la extensión
    • Datos de extensión
  • SHA-1 de 160 bits sobre el contenido del archivo de índice antes de esta suma de comprobación.

mljrg comenta :

Si el índice es el lugar donde se prepara la próxima confirmación, ¿por qué " git ls-files -s" no devuelve nada después de la confirmación?

Debido a que el índice representa lo que se está rastreando , y justo después de una confirmación, lo que se está rastreando es idéntico a la última confirmación ( git diff --cachedno devuelve nada).

Entonces, git ls-files -senumera todos los archivos rastreados (nombre del objeto, bits de modo y número de etapa en la salida).

Esa lista (de elemento rastreado) se inicializa con el contenido de una confirmación.
Cuando cambia de rama, el contenido del índice se restablece a la confirmación a la que hace referencia la rama a la que acaba de cambiar.


Git 2.20 (Q4 2018) agrega una tabla de compensación de entrada de índice (IEOT) :

Ver commit 77ff112 , commit 3255089 , commit abb4bb8 , commit c780b9c , commit 3b1d9e0 , commit 371ed0d (10 de octubre de 2018) por Ben Peart ( benpeart) .
Ver commit 252d079 (26 de septiembre de 2018) por Nguyễn Thái Ngọc Duy ( pclouds) .
(Fusionada por Junio ​​C Hamano - gitster- en commit e27bfaa , 19 oct 2018)

ieot: agregar extensión de tabla de desplazamiento de entrada de índice (IEOT)

Este parche permite abordar el costo de la CPU de cargar el índice agregando datos adicionales al índice que nos permitirán realizar múltiples subprocesos de manera eficiente en la carga y conversión de entradas de caché.

Esto se logra al agregar una extensión de índice (opcional) que es una tabla de compensaciones a bloques de entradas de caché en el archivo de índice.

Para que esto funcione para los índices V4, al escribir las entradas de caché, periódicamente "restablece" la compresión de prefijos al codificar la entrada actual como si el nombre de ruta de la entrada anterior fuera completamente diferente y guardara el desplazamiento de esa entrada en el IEOT .
Básicamente, con los índices V4, genera compensaciones en bloques de entradas comprimidas con prefijo.

Con la nueva configuración de index.threads , la carga del índice ahora es más rápida.


Como resultado ( de usar IEOT ), confirme 7bd9631 limpia la read-cache.c load_cache_entries_threaded()función para Git 2.23 (Q3 2019).

Ver commit 8373037 , commit d713e88 , commit d92349d , commit 113c29a , commit c95fc72 , commit 7a2a721 , commit c016579 , commit be27fb7 , commit 13a1781 , commit 7bd9631 , commit 3c1dce8 , commit cf7a901 , commit d64db5b , commit 76a7b0 ( Jeffpeff May 09b ) ( ) .
(Fusionada por Junio ​​C Hamano - gitster- en commit c0e78f7 , 13 jun 2019)

read-cache: descartar el parámetro no utilizado de la carga roscada

La load_cache_entries_threaded()función toma un src_offsetparámetro que no usa. Esto ha estado allí desde su inicio en 77ff112 ( read-cache: cargar entradas de caché en subprocesos de trabajo, 2018-10-10, Git v2.20.0-rc0).

Excavando en la lista de correo, ese parámetro era parte de una iteración anterior de la serie , pero se volvió innecesario cuando el código cambió para usar la extensión IEOT.

VonC
fuente
66
Sobre la importancia del índice en el modelo Git, consulte stackoverflow.com/questions/1450348/…
VonC
El primer enlace de arriba apunta a una versión de git-scm que no tiene un artículo en el índice. Creo que la intención era señalar aquí: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing
1
@KrisGiesing Gracias por el enlace. He actualizado la respuesta.
VonC
@VonC Si el índice es el lugar donde se prepara la próxima confirmación, ¿por qué "git ls-files -s" no devuelve nada después de la confirmación? Debe haber algo más sobre el índice de lo que ha puesto en su respuesta.
mljrg
@mljrg no estoy seguro de seguirte: después de una confirmación, la etapa (donde se estaba preparando la confirmación) estaría vacía, ya que la confirmación se realizó, ¿no es así?
VonC
62

Análisis bit a bit

He decidido hacer una pequeña prueba para comprender mejor el formato e investigar algunos de los campos con más detalle.

Los resultados a continuación son los mismos para las versiones Git 1.8.5.2y 2.3.

He marcado puntos que no estoy seguro / no he encontrado TODO: por favor, siéntase libre de complementar esos puntos.

Como otros mencionaron, el índice se almacena en .git/index, no como un objeto de árbol estándar, y su formato es binario y está documentado en: https://github.com/git/git/blob/master/Documentation/technical/index-format. TXT

Las estructuras principales que definen el índice están en cache.h , porque el índice es un caché para crear confirmaciones.

Preparar

Cuando comenzamos un repositorio de prueba con:

git init
echo a > b
git add b
tree --charset=ascii

El .gitdirectorio se ve así:

.git/objects/
|-- 78
|   `-- 981922613b2afb6025042ff6bd878ac1994e85
|-- info
`-- pack

Y si obtenemos el contenido del único objeto:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Nosotros conseguimos a. Esto indica que:

  • los indexpuntos al contenido del archivo, ya que git add bcreó un objeto blob
  • almacena los metadatos en el archivo de índice, no en un objeto de árbol, ya que solo había un único objeto: el blob (en objetos Git normales, los metadatos de blob se almacenan en el árbol)

análisis de alta definición

Ahora echemos un vistazo al índice en sí:

hd .git/index

Da:

00000000  44 49 52 43 00 00 00 02  00 00 00 01 54 09 76 e6  |DIRC.... ....T.v.|
00000010  1d 81 6f c6 54 09 76 e6  1d 81 6f c6 00 00 08 05  |..o.T.v. ..o.....|
00000020  00 e4 2e 76 00 00 81 a4  00 00 03 e8 00 00 03 e8  |...v.... ........|
00000030  00 00 00 02 78 98 19 22  61 3b 2a fb 60 25 04 2f  |....x.." a;*.`%./|
00000040  f6 bd 87 8a c1 99 4e 85  00 01 62 00 ee 33 c0 3a  |......N. ..b..3.:|
00000050  be 41 4b 1f d7 1d 33 a9  da d4 93 9a 09 ab 49 94  |.AK...3. ......I.|
00000060

A continuación concluiremos:

  | 0           | 4            | 8           | C              |
  |-------------|--------------|-------------|----------------|
0 | DIRC        | Version      | File count  | ctime       ...| 0
  | ...         | mtime                      | device         |
2 | inode       | mode         | UID         | GID            | 2
  | File size   | Entry SHA-1                              ...|
4 | ...                        | Flags       | Index SHA-1 ...| 4
  | ...                                                       |

Primero viene el encabezado, definido en: struct cache_header :

  • 44 49 52 43: DIRC. TODO: ¿por qué es esto necesario?

  • 00 00 00 02: versión de formato: 2. El formato de índice ha evolucionado con el tiempo. Actualmente existe una versión hasta 4. El formato del índice no debería ser un problema al colaborar entre diferentes computadoras en GitHub porque los repositorios desnudos no almacenan el índice: se genera en tiempo de clonación.

  • 00 00 00 01: recuento de archivos en el índice: solo uno b,.

Luego comienza una lista de entradas de índice, definida por struct cache_entry Aquí tenemos solo una. Contiene:

  • un montón de metadatos de archivo: 8 bytes ctime, 8 bytes mtime, luego 4 bytes: dispositivo, inodo, modo, UID y GID.

    Tenga en cuenta cómo:

    • ctimey mtimeson los mismos ( 54 09 76 e6 1d 81 6f c6) como se esperaba ya que no hemos modificado el archivo

      Los primeros bytes son segundos desde EPOCH en hexadecimal:

      date --date="@$(printf "%x" "540976e6")"
      

      Da:

      Fri Sep  5 10:40:06 CEST 2014
      

      Que es cuando hice este ejemplo.

      Los segundos 4 bytes son nanosegundos.

    • UID y GID son 00 00 03 e81000 en hexadecimal: un valor común para configuraciones de usuario único.

    Todos estos metadatos, la mayoría de los cuales no están presentes en los objetos del árbol, le permiten a Git verificar si un archivo ha cambiado rápidamente sin comparar todo el contenido.

  • al principio de la línea 30:: 00 00 00 02tamaño del archivo: 2 bytes ( ay \nde echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 bytes SHA-1 sobre el contenido anterior de la entrada. Tenga en cuenta que de acuerdo con mis experimentos con el indicador de asumir válido , los indicadores que lo siguen no se consideran en este SHA-1.

  • Banderas de 2 bytes: 00 01

    • 1 bit: asume un indicador válido. Mis investigaciones indican que esta bandera mal nombrada es donde git update-index --assume-unchangedalmacena su estado: https://stackoverflow.com/a/28657085/895245

    • Bandera extendida de 1 bit. Determina si las banderas extendidas están presentes o no. Debe estar 0en la versión 2 que no tiene banderas extendidas.

    • Indicador de etapa de 2 bits utilizado durante la fusión. Las etapas están documentadas en man git-merge:

      • 0: archivo normal, no en un conflicto de fusión
      • 1: base
      • 2: el nuestro
      • 3: de ellos

      Durante un conflicto de fusión, todas las etapas de 1-3 se almacenan en el índice para permitir operaciones como git checkout --ours.

      Si es así git add, se agrega una etapa 0 al índice de la ruta, y Git sabrá que el conflicto se ha marcado como resuelto. TODO: mira esto.

    • Longitud de 12 bits de la ruta que seguirá 0 01: 1 byte solo desde que la ruta fueb

  • Banderas extendidas de 2 bytes. Solo tiene sentido si el "indicador extendido" se estableció en los indicadores básicos. QUE HACER.

  • 62(ASCII b): ruta de longitud variable. Longitud determinada en los pabellones anteriores, aquí sólo 1 byte, b.

Luego viene un 00: 1-8 bytes de relleno cero para que la ruta sea terminada en nulo y el índice termine en un múltiplo de 8 bytes. Esto solo ocurre antes de la versión de índice 4.

No se utilizaron extensiones. Git lo sabe porque no quedaría suficiente espacio en el archivo para la suma de comprobación.

Finalmente, hay una suma de verificación de 20 bytes ee 33 c0 3a .. 09 ab 49 94sobre el contenido del índice.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
fuente
1
Muy interesante. +1. Eso ilustra mi propia respuesta muy bien. Me pregunto si esos resultados cambiarían con el último Git 2.1+.
VonC
3
@NielsBom sí, eso también funcionaría. Al interpretar programas, prefiero adoptar dos enfoques: primero empírico para ver qué resultados genera, y solo luego leer la fuente. De lo contrario, uno podría quedar atrapado en casos extremos del código fuente que ni siquiera aparecen en salidas simples. Por supuesto, miré las estructuras de origen para ayudar a guiarme, y cada TODO puede resolverse en mi lectura de cómo se manipulan esas estructuras, que es la parte difícil.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: Si modifico el índice en un editor hexadecimal y actualizo su suma de verificación de 20 bytes, ¿hay un comando para actualizar el sha1 que está almacenado en otros objetos? (Git se queja de que la firma sha1 del índice está corrupta) . Además, los datos de índice se almacenan de una manera completamente diferente cuando se envían a través de solicitudes push.
usuario2284570
1
@CiroSantilli 六四 事件 法轮功 纳米比亚 威 视: fines de seguridad. Simplemente buscando el tipo bien conocido de ataques de archivos de imagen ráster aplicados a la base de datos / objetos git. (por supuesto, sé que la mayor parte de la implementación se ocupó recientemente de esa perspectiva, pero probablemente no de todas)  Así que estoy buscando especialmente estructuras de datos binarios que indiquen la longitud de una matriz. (con respecto a los búferes de texto, parece que la terminación nula es la norma para indicar el número de filas)
user2284570
1
En cuanto a git add, por su TODO: tiene razón. Si tiene entradas de índice de etapa alta (un conflicto) en una ruta determinada, cuando use git addesa ruta, todas las entradas de índice de etapa alta se eliminarán y la copia del directorio de trabajo se agregará en la etapa 0. (Resolviendo el conflicto).
Edward Thomson el
11

El índice Git es un área de ensayo entre su directorio de trabajo y su repositorio. Puede usar el índice para crear un conjunto de cambios que desea confirmar juntos. Cuando crea una confirmación, lo que se confirma es lo que está actualmente en este índice, no lo que está en su directorio de trabajo.

Para ver qué hay dentro del índice, emita el comando:

git status

Cuando ejecuta el estado de git, puede ver qué archivos están almacenados (actualmente en su índice), cuáles están modificados pero aún no almacenados, y cuáles están completamente sin seguimiento.

Puedes leer esto . Una búsqueda en Google arroja muchos enlaces, que deberían ser bastante autosuficientes.

usuario225312
fuente
77
git statusno enumera todos los archivos del índice. Solo enumera aquellos archivos que difieren entre el índice y el directorio de trabajo. Para ver todos los archivos en el índice, debe usar git ls-files.
Akash Agrawal
1
@AkashAgrawal, git status lo hace en los archivos de índice de la lista de hecho, con independencia de que difieren entre el índice y workdir.
Acumenus
3
sí, enumera ALGUNOS de los archivos de índice, pero no le muestra todo lo que está dentro del índice, que es lo que dice su declaración en su respuesta. Es como decir que hay 2 bolas verdes y 3 bolas rojas dentro de una caja. Para ver qué hay dentro de la caja, saca las 2 bolas verdes. Lo que Akash dijo es más preciso: para ver todos los archivos en el índice, use git ls-files.
dave4jr
3
En efecto. git statusenumera los archivos que están en el índice, sí, pero no enumera todos los archivos en el índice. Explicar cómo funciona git status realmente sería una respuesta beneficiosa a alguna pregunta, aunque probablemente no esta.
Edward Thomson el
1
git statusmuestra el estado del árbol de trabajo (diferencia entre el árbol de trabajo y el índice). En realidad no muestra el índice. git-scm.com/docs/git-status
wisbucky
1

Esto es exactamente lo que necesita, use este comando.

$ binwalk index

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
1717          0x6B5           Unix path: /company/user/user/delete.php
1813          0x715           Unix path: /company/user/user/get.php
1909          0x775           Unix path: /company/user/user/post.php
2005          0x7D5           Unix path: /company/user/user/put.php
3373          0xD2D           Unix path: /urban-airship/channel/channel/post.php
3789          0xECD           Unix path: /urban-airship/named-user/named-user/post.php
3901          0xF3D           Unix path: /user/categories/categories/delete.php
4005          0xFA5           Unix path: /user/categories/categories/get.php
4109          0x100D          Unix path: /user/categories/categories/put.php
4309          0x10D5          Unix path: /user/favorites/favorites/delete.php
lh
fuente
0

El índice Git es un archivo binario (generalmente guardado .git/index) que contiene una lista ordenada de nombres de ruta, cada uno con permisos y el SHA1 de un objeto blob;

git ls-filespuede mostrarle el contenido del índice. Tenga en cuenta que las palabras index, stagey cacheson lo mismo en Git: se usan indistintamente.

ingrese la descripción de la imagen aquí

El índice Git, o caché Git, tiene 3 propiedades importantes:

  1. El índice contiene toda la información necesaria para generar un único objeto de árbol (determinado de forma única).
  2. El índice permite comparaciones rápidas entre el objeto del árbol que define y el árbol de trabajo.
  3. Puede representar de manera eficiente información sobre conflictos de fusión entre diferentes objetos de árbol, permitiendo que cada nombre de ruta se asocie con información suficiente sobre los árboles involucrados para que pueda crear una fusión tripartita entre ellos.

Fuente :

  1. https://mincong.io/2018/04/28/git-index/
  2. https://medium.com/hackernoon/understanding-git-index-4821a0765cf
Saikat
fuente