O que o git está realmente fazendo quando diz que está "resolvendo deltas"?

187

Durante o primeiro clone de um repositório, o git primeiro recebe os objetos (o que é bastante óbvio) e depois passa a mesma quantidade de tempo "resolvendo deltas". O que realmente está acontecendo durante esta fase do clone?

Nik Reiman
fonte
Related: stackoverflow.com/questions/9478023/…
Ciro Santilli escreveu:
1
Consulte também, para o Git 2.20 (quarto trimestre de 2018) e mais ilhas delta: stackoverflow.com/a/52458712/6309
VonC

Respostas:

54

O Git usa codificação delta para armazenar alguns dos objetos em arquivos de pacote. No entanto, você não quer ter que reproduzir cada mudança sempre em um determinado arquivo, a fim de obter a versão atual, de modo Git também tem instantâneos ocasionais do conteúdo do arquivo armazenados também. "Resolver deltas" é a etapa que trata de garantir que tudo isso permaneça consistente.

Aqui está um capítulo da seção "Git Internals" do livro Pro Git, disponível on-line, que fala sobre isso.

Âmbar
fonte
80
Esta resposta está incorreta. Parece descrever como o Mercurial funciona, não o Git. Está chegando nas pesquisas do Google para esse problema, então sinto a necessidade de responder. O Git não armazena as diferenças entre confirmações como deltas; Git é uma loja de "objeto inteiro". Como tal, o Git não precisa de "snapshots" para mostrar qualquer arquivo, porque o histórico do arquivo não precisa ser reconstruído a partir de deltas. É assim que o Mercurial funciona.
Nexus diz 15/01
12
O único lugar em que a codificação delta entra em cena é o arquivo do pacote, estritamente para compactação e transferência - não altera a maneira como o Git "vê" o mundo. ( kernel.org/pub/software/scm/git/docs/v1.6.2.3/technical/… ) Consulte a resposta do araqnid abaixo para obter uma resposta precisa.
nexus diz 15/01
4
Todo "instantâneo" significa que, neste contexto, é uma cópia completa de um estado de arquivo, em vez de uma versão codificada em delta. Como você mencionou, Git faz uso delta-codificação em packfiles. Ninguém disse que "altera a forma como o Git vê o mundo"; pare de projetar suas próprias suposições.
22613 Amber
2
Sua resposta ainda é imprecisa. "O Git também possui capturas instantâneas ocasionais do conteúdo do arquivo armazenado." -- Isso não é correto. "'Resolver deltas' é a etapa que trata de garantir que tudo isso permaneça consistente." - isso também não está correto, a resposta do araqnid abaixo está correta.
Nexus diz 22/01
1
Conforme descrito no capítulo mencionado acima, o Git armazena sempre o conteúdo completo da versão mais recente. As versões anteriores são armazenadas como arquivos codificados em delta quando são arquivos "frouxos". Periodicamente (chamando git gcou sempre que o Git determinar necessário), o Git compactará todos os arquivos "frouxos" em um arquivo de pacote para economizar espaço e um arquivo de índice nesse pacote será criado. Portanto, o zlib compactará com seu próprio algoritmo delta, mas o Git usa a codificação delta para armazenar versões anteriores. Como o acesso mais comum e frequente é a versão mais recente, ela é armazenada como uma captura instantânea.
BrionS
118

Os estágios de git clonesão:

  1. Receba um arquivo "pack" de todos os objetos no banco de dados repo
  2. Crie um arquivo de índice para o pacote recebido
  3. Confira a revisão principal (para um repo não nu, obviamente)

"Resolvendo deltas" é a mensagem mostrada para o segundo estágio, indexando o arquivo do pacote ("git index-pack").

Os arquivos do pacote não possuem os IDs reais do objeto, apenas o conteúdo do objeto. Portanto, para determinar quais são os IDs de objeto, o git precisa descomprimir + SHA1 de cada objeto no pacote para produzir o ID do objeto, que é gravado no arquivo de índice.

Um objeto em um arquivo de pacote pode ser armazenado como um delta, ou seja, uma sequência de alterações a serem feitas em outro objeto. Nesse caso, o git precisa recuperar o objeto base, aplicar os comandos e SHA1 o resultado. O próprio objeto base pode ter que ser derivado aplicando uma sequência de comandos delta. (Mesmo que no caso de um clone, o objeto base já tenha sido encontrado, há um limite para quantos objetos fabricados estão armazenados em cache na memória).

Em resumo, o estágio "resolvendo deltas" envolve a descompactação e soma de verificação de todo o banco de dados do repositório, o que não surpreendentemente leva muito tempo. Presumivelmente, descomprimir e calcular SHA1s realmente leva mais tempo do que aplicar os comandos delta.

No caso de uma busca subsequente, o arquivo de pacote recebido pode conter referências (como bases de objetos delta) a outros objetos que o git de recebimento já deve ter. Nesse caso, o git de recebimento realmente reescreve o arquivo de pacote recebido para incluir quaisquer objetos referenciados, para que qualquer arquivo de pacote armazenado seja auto-suficiente. Pode ser onde a mensagem "resolvendo deltas" se originou.

araqnid
fonte
7
Isso pode ser paralelo?
precisa
Essa compactação delta é mais do que armazenar vários objetos em um fluxo de dados zlib?
fuz 4/03/2015
1
@FUZxxl sim, é usando um algoritmo como diff ou xdelta para comparar duas bolhas e produzir um roteiro de edição
araqnid
@brooksbp: Apenas com limitações. Como o objeto com o ID 103fa49 pode precisar que o df85b51 seja decodificado, mas quando você recebe 103fa49, o df85b51 ainda não está lá (os arquivos do pacote são estritamente ordenados por sha1 hashes). Portanto, para tudo que faz referência apenas a coisas que já estão lá, as coisas são fáceis, mas para todo o resto, você terá que esperar até que seja recebido. E essa compactação delta pode ser aninhada, portanto 103fa49 pode precisar de 4e9ba42, que por sua vez precisa de 29ad945, que por sua vez precisa de c9e645a ... você entendeu. [sim, eu notei que faz mais de 4 anos;)]
Bodo Thiesen
2
@brooksbp: Acontece que eu estava errado, o arquivo do pacote NÃO precisa ser classificado por hashes sha1. Além disso, ao escrever, o git grava os objetos necessários antes dos objetos que precisam deles. Então, na verdade você deve ser capaz de paralelizar isso. A única desvantagem que permanece: como você não sabe quais objetos precisará mais tarde, precisará recriar alguns e outra vez. Veja aqui: kernel.org/pub/software/scm/git/docs/technical/…
Bodo Thiesen
4

O âmbar parece estar descrevendo o modelo de objeto que o Mercurial ou similar usa. O Git não armazena os deltas entre versões subseqüentes de um objeto, mas instantâneos completos do objeto, todas as vezes. Em seguida, compacta esses instantâneos usando a compactação delta, tentando encontrar bons deltas para usar, independentemente de onde no histórico eles existam.

Johan
fonte
5
Na verdade, embora o Git possa armazenar objetos soltos, eles nem sempre são armazenados como tais - pois os objetos soltos podem ser excluídos e substituídos pelo conteúdo compactado. Não acho que a resposta de Amber tenha dito nada sobre as versões subseqüentes.
AlBlue