O que o índice git contém EXATAMENTE?

O que o índice do 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 funciona como uma área de preparação, e o que está comprometido está no índice e não na tree de trabalho. Estou apenas curioso sobre o que consiste em um object de índice. Eu acho que pode ser uma lista de nome do arquivo / diretório, pares SHA-1, um tipo de tree virtual, talvez?

Existe, na terminologia do Git, qualquer comando de encanamento que eu possa usar para listar o conteúdo do índice?

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

O índice é um arquivo binário (geralmente mantido em .git/index ) contendo uma lista ordenada de nomes de caminhos, cada um com permissions e o SHA1 de um object blob; git ls-files pode mostrar o conteúdo do índice:

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

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

O índice é uma das estruturas de dados mais importantes no git.
Ele representa um estado de tree de trabalho virtual, registrando a lista de caminhos e seus nomes de objects e serve como uma área de preparação para gravar o próximo object de tree a ser confirmado.
O estado é “virtual” no sentido de que não precisa necessariamente corresponder aos arquivos na tree de trabalho.


Para ver mais, cf. ” git / git / Documentação / technical / index-format.txt “:

O arquivo de índice do Git tem o seguinte formato

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

  • Um header de 12 bytes consistindo em:
    • Assinatura de 4 bytes:
      A assinatura é {‘ D ‘, ‘ I ‘, ‘ R ‘, ‘ C ‘} (significa ” dircache “)
    • Número da versão de 4 bytes:
      As versões atuais suportadas são 2, 3 e 4.
    • Número de 32 bits de inputs de índice.
  • Um número de inputs de índice ordenadas.
  • Extensões :
    Extensões são identificadas por assinatura.
    Extensões opcionais podem ser ignoradas se o Git não as entender.
    O Git atualmente suporta tree em cache e resolve 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 sum de verificação.

Comentários mljrg :

Se o índice é o lugar onde o próximo commit é preparado, por que o ” git ls-files -s ” não retorna nada após o commit?

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 --cached não retorna nada).

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

Essa lista (do 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.

Análise pouco a pouco

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 1.8.5.2 e 2.3 Git.

Marquei pontos que não tenho certeza / não encontrei no TODO : sinta-se à vontade para complementar esses pontos.

Como outros mencionaram, o índice é armazenado em .git/index , não como um object de tree padrão, e seu formato é binário e documentado em: https://github.com/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 criar confirmações.

Configuração

Quando iniciamos um repository de teste com:

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

O diretório .git parece com:

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

E se conseguirmos o conteúdo do único object:

 git cat-file -p 78981922613b2afb6025042ff6bd878ac1994e85 

Nós temos a . Isso indica que:

  • o index aponta para o conteúdo do arquivo, já que o git add b criou um object blob
  • armazena os metadados no arquivo de índice, não em um object de tree, já que havia apenas um único object: o blob (em objects Git comuns, os metadados de blob são armazenados na tree)

análise hd

Agora vamos olhar para o índice em si:

 hd .git/index 

Dá:

 00000000 44 49 52 43 00 00 00 02 00 00 00 01 54 09 76 e6 |DIRC.... ....Tv| 00000010 1d 81 6f c6 54 09 76 e6 1d 81 6f c6 00 00 08 05 |..oTv ..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 

Em seguida, vamos concluir:

  | 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 header, definido em: struct cache_header :

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

  • 00 00 00 02 : versão do formato: 2. O formato do índice evoluiu com o tempo. Atualmente, existe a versão até 4. O formato do índice não deve ser um problema ao colaborar entre diferentes computadores no GitHub, pois os repositorys vazios não armazenam o índice: ele é gerado no momento da clonagem.

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

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

  • um monte de metadados de arquivo: 8 byte ctime , 8 byte mtime , depois 4 byte: device, inode, modo, UID e GID.

    Observe como:

    • ctime e mtime são os mesmos ( 54 09 76 e6 1d 81 6f c6 ) como esperado, 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 este exemplo.

      Os segundos 4 bytes são nanossegundos.

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

    Todos esses metadados, a maioria dos quais não está presente em objects de tree, permitem ao Git verificar se um arquivo foi alterado rapidamente sem comparar todo o conteúdo.

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

  • 78 98 19 22 ... c1 99 4e 85 : 20 byte SHA-1 sobre o conteúdo anterior da input. Observe que, de acordo com meus experimentos com a bandeira assume , os sinalizadores que seguem 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 nome ruim é onde git update-index --assume-unchanged armazena seu estado: https://stackoverflow.com/a/28657085/895245

    • Bandeira estendida de 1 bit. Determina se os sinalizadores estendidos estão presentes ou não. Deve ser 0 na versão 2, que não possui sinalizadores estendidos.

    • Bandeira de estágio de 2 bits usada durante a mesclagem. Estágios são documentados 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 , então um estágio 0 será adicionado ao índice para o caminho, e o Git saberá que o conflito foi marcado como resolvido. TODO: verifique isso.

    • Comprimento de 12 bits do caminho que seguirá: 0 01 : 1 byte somente desde que o caminho foi b

  • Sinalizadores estendidos de 2 bytes. Somente significativo se o “sinalizador estendido” tiver sido definido nas sinalizações básicas. FAÇAM.

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

Em seguida, vem um 00 : 1-8 bytes de zero preenchimento para que o caminho será terminado por nulo e o índice terminará em um múltiplo de 8 bytes. Isso só acontece antes da versão do índice 4.

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

Finalmente, há um checksum de 20 bytes ee 33 c0 3a .. 09 ab 49 94 sobre o conteúdo do índice.

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

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

 git status 

Quando você executa o status git, você pode ver quais arquivos são preparados (atualmente no seu índice), que são modificados, mas ainda não estão em estágios, e que são completamente não acompanhados.

Você pode ler isso . Uma pesquisa no Google gera muitos links, o que deve ser bastante auto-suficiente.