O que o índice git contém EXATAMENTE?

178

O que o índice Git contém exatamente e qual comando posso usar para visualizar o conteúdo do índice?


Atualizar

Obrigado por todas as suas respostas. Eu sei que o índice atua como uma área de preparação, e o que está comprometido está no índice e não na árvore de trabalho. Estou apenas curioso sobre o que consiste um objeto de índice. Eu acho que pode ser uma lista de nome de arquivo / diretório, pares SHA-1, uma espécie de árvore virtual, talvez?

Existe, na terminologia Git, algum comando de canalização que eu possa usar para listar o conteúdo do índice?

mochidino
fonte
3
você deve ler e assistir diagramas - muito útil: gitguys.com/topics/whats-the-deal-with-the-git-index
kernix
1
@kernix o domínio expirou. Não é mais muito útil.
Narendra-choudhary

Respostas:

162

O livro Git contém um artigo sobre o que um índice inclui :

O índice é um arquivo binário (geralmente mantido .git/index) contendo uma lista classificada de nomes de caminhos, cada um com permissões e o SHA1 de um objeto de blob; git ls-filespode mostrar o conteúdo do índice:

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

O problema do Racy git fornece mais alguns detalhes sobre essa estrutura:

O índice é uma das estruturas de dados mais importantes no git.
Ele representa um estado da árvore de trabalho virtual gravando a lista de caminhos e seus nomes de objetos e serve como uma área intermediária para gravar o próximo objeto de árvore a ser confirmado.
O estado é "virtual" no sentido de que não precisa necessariamente, e geralmente não corresponde, aos arquivos na árvore de trabalho.


Para ver mais, cf. " git / git / Documentation / technical / index-format.txt ":

O arquivo de índice Git tem o seguinte formato

Todos os números binários estão na ordem dos bytes da rede.
A versão 2 é descrita aqui, salvo indicação em contrário.

  • Um cabeçalho de 12 bytes que consiste em:
    • Assinatura de 4 bytes :
      a assinatura é {' D', ' I', ' R', ' C'} (significa " dircache")
    • Número da versão de 4 bytes :
      as versões suportadas atualmente são 2, 3 e 4.
    • Número de 32 bits de entradas de índice.
  • Um número de entradas de índice classificadas .
  • Extensões : as
    extensões são identificadas por assinatura.
    Extensões opcionais podem ser ignoradas se o Git não as entender.
    Atualmente, o Git suporta a árvore em cache e resolve as extensões de desfazer.
    • Assinatura de extensão de 4 bytes. Se o primeiro byte for ' A' .. ' Z', a extensão é opcional e pode ser ignorada.
    • Tamanho de 32 bits da extensão
    • Dados de extensão
  • SHA-1 de 160 bits sobre o conteúdo do arquivo de índice antes desta soma de verificação.

mljrg comentários :

Se o índice é o local onde a próxima consolidação é preparada, por que " git ls-files -s" não retorna nada após a consolidação?

Como o índice representa o que está sendo rastreado e logo após um commit, o que está sendo rastreado é idêntico ao último commit ( git diff --cachednão retorna nada).

Então, git ls-files -slista todos os arquivos rastreados (nome do objeto, bits de modo e número do estágio na saída).

Essa lista (de elemento rastreado) é inicializada com o conteúdo de uma confirmação.
Quando você alterna a ramificação, o conteúdo do índice é redefinido para o commit referenciado pela ramificação para a qual você acabou de alternar.


O Git 2.20 (quarto trimestre de 2018) adiciona uma tabela de deslocamento de entrada de índice (IEOT) :

Consulte commit 77ff112 , commit 3255089 , commit abb4bb8 , commit c780b9c , commit 3b1d9e0 , commit 371ed0d (10 de outubro de 2018) por Ben Peart ( benpeart) .
Veja commit 252d079 (26 de setembro de 2018) de Nguyễn Thái Ngọc Duy ( pclouds) .
(Mesclado por Junio ​​C Hamano - gitster- in commit e27bfaa , 19 de outubro de 2018)

ieot: adicionar extensão da tabela de deslocamento de entrada de índice (IEOT)

Esse patch permite abordar o custo da CPU de carregar o índice adicionando dados adicionais ao índice que nos permitirá multiencadear com eficiência o carregamento e a conversão de entradas de cache.

Isso é feito adicionando uma extensão de índice (opcional) que é uma tabela de compensações a blocos de entradas de cache no arquivo de índice.

Para que isso funcione nos índices V4, ao gravar as entradas de cache, "redefine" periodicamente a compactação do prefixo, codificando a entrada atual como se o nome do caminho da entrada anterior fosse completamente diferente e salvasse o deslocamento dessa entrada no IEOT .
Basicamente, com índices V4, ele gera deslocamentos em blocos de entradas compactadas com prefixo.

Com a nova configuração de configuração index.threads , o carregamento do índice agora é mais rápido.


Como resultado ( do uso do IEOT ), confirme 7bd9631 para limpar a read-cache.c load_cache_entries_threaded()função do Git 2.23 (terceiro trimestre de 2019).

Veja cometer 8373037 , cometer d713e88 , cometer d92349d , cometer 113c29a , cometer c95fc72 , cometer 7a2a721 , cometer c016579 , cometer be27fb7 , cometer 13a1781 , cometer 7bd9631 , cometer 3c1dce8 , cometer cf7a901 , cometer d64db5b , cometer 76a7bc0 (09 de maio de 2019) por Jeff King ( peff) .
(Incorporado por Junio ​​C Hamano - gitster- in commit c0e78f7 , 13 jun 2019)

cache de leitura: elimina o parâmetro não utilizado da carga encadeada

A load_cache_entries_threaded()função usa um src_offsetparâmetro que não usa. Isso existe desde a sua criação em 77ff112 ( read-cache: carregar entradas de cache nos threads de trabalho, 10/10/2018, Git v2.20.0-rc0).

Ao pesquisar na lista de discussão, esse parâmetro fazia parte de uma iteração anterior da série , mas se tornou desnecessário quando o código passou a usar a extensão IEOT.

VonC
fonte
6
Sobre a importância do índice no modelo Git, consulte stackoverflow.com/questions/1450348/…
VonC
O primeiro link acima aponta para uma versão do git-scm que não possui um artigo no índice. Eu acho que a intenção era apontar aqui: schacon.github.io/gitbook/7_the_git_index.html
Kris Giesing
1
@KrisGiesing Obrigado pelo link. Eu atualizei a resposta.
VonC 01/09
@VonC Se o índice é o local onde a próxima confirmação é preparada, por que "git ls-files -s" não retorna nada após a confirmação? Deve haver algo mais sobre o índice do que você colocou na sua resposta.
mljrg
@mljrg não tenho certeza se eu te sigo: após um commit, o estágio (onde o commit estava sendo preparado) ficaria vazio, já que o commit foi feito, não seria?
VonC 26/04
62

Análise bit a bit

Decidi fazer um pequeno teste para entender melhor o formato e pesquisar alguns dos campos com mais detalhes.

Os resultados abaixo são os mesmos para as versões Git 1.8.5.2e 2.3.

Marquei pontos com os quais não tenho certeza / não encontrei TODO: fique à vontade para complementar esses pontos.

Como outros mencionados, o índice é armazenado em .git/index, não como um objeto de árvore padrão, e seu formato é binário e documentado em: https://github.com/git/git/git/blob/master/Documentation/technical/index-format. TXT

As principais estruturas que definem o índice estão em cache.h , porque o índice é um cache para a criação de confirmações.

Configuração

Quando iniciamos um repositório de teste com:

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

O .gitdiretório se parece com:

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

E se obtivermos o conteúdo do único objeto:

git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85

Nós recebemos a. Isso indica que:

  • os indexpontos para o conteúdo do arquivo, pois git add bcriou um objeto blob
  • ele armazena os metadados no arquivo de índice, não em um objeto em árvore, pois havia apenas um único objeto: o blob (em objetos Git regulares, os metadados em blob são armazenados na árvore)

análise hd

Agora vamos ver o próprio índice:

hd .git/index

Dá:

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 seguir, 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
  | ...                                                       |

Primeiro vem o cabeçalho, definido em: struct cache_header :

  • 44 49 52 43: DIRC. TODO: por que isso é necessário?

  • 00 00 00 02: format version: 2. O formato do índice evoluiu com o tempo. Atualmente, existe uma versão até 4. O formato do índice não deve ser um problema ao colaborar entre computadores diferentes no GitHub, porque repositórios vazios não armazenam o índice: ele é gerado no momento do clone.

  • 00 00 00 01: contagem de arquivos no índice: apenas um b,.

Em seguida, inicia uma lista de entradas de índice, definidas por struct cache_entry Aqui temos apenas uma. Contém:

  • vários metadados de arquivo: 8 bytes ctime, 8 bytes mtimee 4 bytes: dispositivo, inode, modo, UID e GID.

    Observe como:

    • ctimee mtimesão os mesmos ( 54 09 76 e6 1d 81 6f c6) esperados, pois não modificamos o arquivo

      Os primeiros bytes são segundos desde EPOCH em hexadecimal:

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

      Dá:

      Fri Sep  5 10:40:06 CEST 2014
      

      Foi quando eu fiz esse exemplo.

      Os segundos 4 bytes são nanossegundos.

    • UID e GID são 00 00 03 e81000 em hexadecimal: um valor comum para configurações de usuário único.

    Todos esses metadados, a maioria dos quais não está presente nos objetos da árvore, permitem ao Git verificar se um arquivo mudou rapidamente sem comparar o conteúdo inteiro.

  • no início da linha 30:: 00 00 00 02tamanho do arquivo: 2 bytes ( ae \nde echo)

  • 78 98 19 22 ... c1 99 4e 85: 20 bytes SHA-1 sobre o conteúdo anterior da entrada. Observe que, de acordo com minhas experiências com o sinalizador assumido válido , os sinalizadores a seguir não são considerados neste SHA-1.

  • Sinalizadores de 2 bytes: 00 01

    • 1 bit: assume sinalizador válido. Minhas investigações indicam que esse sinalizador com nomes inadequados é onde git update-index --assume-unchangedarmazena seu estado: https://stackoverflow.com/a/28657085/895245

    • Sinalizador estendido de 1 bit. Determina se os sinalizadores estendidos estão presentes ou não. Deve estar 0na versão 2 que não possui sinalizadores estendidos.

    • Sinalizador de estágio de 2 bits usado durante a mesclagem. As etapas estão documentadas em man git-merge:

      • 0: arquivo regular, não em conflito de mesclagem
      • 1: base
      • 2: nosso
      • 3: deles

      Durante um conflito de mesclagem, todos os estágios de 1 a 3 são armazenados no índice para permitir operações como git checkout --ours.

      Se você git add, um estágio 0 é adicionado ao índice do caminho, e o Git saberá que o conflito foi marcado como resolvido. TODO: verifique isso.

    • Comprimento de 12 bits do caminho a seguir 0 01:: 1 byte somente desde que o caminho foib

  • Sinalizadores estendidos de 2 bytes. Somente significativo se o "sinalizador estendido" tiver sido definido nos sinalizadores básicos. FAÇAM.

  • 62(ASCII b): caminho de comprimento variável. Comprimento determinado nos sinalizadores anteriores, aqui apenas 1 byte b,.

Em seguida, vem 00: 1-8 bytes de preenchimento zero, para que o caminho seja nulo e o índice termine em um múltiplo de 8 bytes. Isso acontece apenas antes da versão 4 do índice.

Nenhuma extensão foi usada. O Git sabe disso porque não haveria espaço suficiente no arquivo para a soma de verificação.

Finalmente, há uma soma de verificação de 20 bytes ee 33 c0 3a .. 09 ab 49 94sobre o conteúdo do índice.

Ciro Santilli adicionou uma nova foto
fonte
1
Muito interessante. +1. Isso ilustra bem minha própria resposta . Gostaria de saber se esses resultados mudariam com o mais recente Git 2.1+.
VonC 15/09/14
3
@ NielsBom sim, isso também funcionaria. Ao interpretar programas, prefiro adotar duas abordagens: primeiro empírica para ver quais saídas ele gera e só então ler a fonte. Caso contrário, pode-se encontrar casos extremos de código-fonte que nem aparecem em saídas simples. Obviamente, observei as estruturas de origem para ajudar a me orientar, e todo TODO pode ser resolvido na minha leitura de como essas estruturas são manipuladas, o que é a parte mais difícil.
Ciro Santilli # 14/15
1
@CiroSantilli 视 事件 法轮功 纳米比亚 威: Se eu modificar o índice em um editor hexadecimal e atualizar a soma de verificação de 20 bytes, existe um comando para atualizar o sha1 que está armazenado em outros objetos? (o git reclama que a assinatura do índice sha1 está corrompida) . Os dados do índice também são armazenados de uma maneira completamente diferente quando enviados por solicitações push.
user2284570
1
@CiroSantilli 视 事件 法轮功 纳米比亚 威 视: fins de segurança. Apenas procurando o tipo bem conhecido de ataques de arquivos de imagem raster aplicados ao banco de dados / objetos git. (é claro que eu sei que a maioria das implementações cuidou recentemente dessa perspectiva, mas provavelmente não todas).  Portanto, estou procurando especialmente estruturas de dados binários que digam o tamanho de uma matriz. (sobre buffers de texto parece terminação nula é a norma para contar o número de linhas)
user2284570
1
Em relação git addao seu TODO: você está correto. Se você tiver entradas de índice de alto estágio (um conflito) em um determinado caminho, quando você tiver git addesse caminho, todas as entradas de índice de alto estágio serão removidas e a cópia do diretório de trabalho será adicionada no estágio 0. (Resolvendo o conflito).
Edward Thomson
11

O índice Git é uma área intermediária entre o diretório ativo e o repositório. Você pode usar o índice para criar um conjunto de alterações que deseja confirmar juntos. Quando você cria uma confirmação, o que é confirmado é o que está atualmente neste índice, não o que está no seu diretório de trabalho.

Para ver o que está dentro do índice, emita o comando:

git status

Ao executar o status do git, é possível ver quais arquivos estão preparados (atualmente no seu índice), quais foram modificados, mas ainda não estão preparados, e quais não estão completamente rastreados.

Você pode ler isso . Uma pesquisa no Google exibe muitos links, que devem ser bastante auto-suficientes.

user225312
fonte
7
git statusnão lista todos os arquivos do índice. Ele lista apenas os arquivos que diferem entre o índice e o diretório de trabalho. Para ver todos os arquivos no índice, você precisa usar git ls-files.
Akash Agrawal
1
@AkashAgrawal, git status faz em arquivos de índice de lista verdade, independentemente de eles diferem entre o índice e workdir.
Acumenus
3
sim, lista ALGUNS dos arquivos de índice, mas não mostra tudo o que está dentro do índice, que é o que a declaração dele em sua resposta diz. É como dizer que existem 2 bolas verdes e 3 vermelhas dentro de uma caixa. Para ver o que há dentro da caixa, retire as 2 bolas verdes. O que Akash disse é mais preciso: para ver todos os arquivos no índice, use git ls-files.
Dave4jr
3
De fato. git statuslista os arquivos que estão no índice, sim, mas não lista todos os arquivos no índice. Explicar como git status realmente funciona seria uma resposta benéfica para alguma pergunta, embora provavelmente não seja essa.
Edward Thomson
1
git statusmostra o status da árvore de trabalho (diferença entre a árvore de trabalho e o índice). Na verdade, ele não mostra o índice. git-scm.com/docs/git-status
wisbucky 28/11
1

Aqui está exatamente o que você precisava, 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
fonte
0

O índice Git é um arquivo binário (geralmente mantido em .git/index) contendo uma lista classificada de nomes de caminhos, cada um com permissões e o SHA1 de um objeto de blob;

git ls-filespode mostrar o conteúdo do índice. Por favor, note que as palavras index, stagee cachesão a mesma coisa em Git: eles são usados de forma intercambiável.

insira a descrição da imagem aqui

O índice Git, ou cache Git, possui três propriedades importantes:

  1. O índice contém todas as informações necessárias para gerar um único objeto de árvore (determinado exclusivamente).
  2. O índice permite comparações rápidas entre o objeto de árvore que define e a árvore de trabalho.
  3. Ele pode representar com eficiência informações sobre conflitos de mesclagem entre diferentes objetos da árvore, permitindo que cada nome de caminho seja associado a informações suficientes sobre as árvores envolvidas, para que você possa criar uma mesclagem de três vias entre elas.

Fonte :

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