Verificações de Integridade de Metadados do Git?


1

Eu queria saber hoje como o git garante a integridade de seus metadados e estou um pouco surpreso com o que encontrei. Eu usei a seguinte configuração simples para testar:

  • Dois repositórios de trabalho, chamados x e y
  • Um repositório nu, chamado xy.git

Então, inicialmente x e y estão empurrando para e puxando de x.git e tudo funciona bem. Agora, digamos que um dos objetos de metadados ( .git/objects/... ) em x.git torna-se corrompido por qualquer motivo (escolha o seu incidente aleatório favorito).

Eu estava realmente assumindo que algo vai quebrar no próximo push ou pull, mas para minha surpresa, tudo parecia funcionar bem. Mais se compromete, mais empurrando e puxando, sem problemas. A primeira vez que algo foi relatado como corrompido foi quando tentei clonar outro repositório de trabalho do repositório vazio, deixando meu clone em um estado inutilizável.

Agora eu pensei que não é tão ruim assim, porque graças à arquitetura do git, eu posso simplesmente despejar o repositório vazio no pior dos casos, e recriá-lo com todo o histórico de um dos meus conjuntos de trabalho. Mas não. Sem aviso prévio, o arquivo corrompido passou pelos repositórios de trabalho, impossibilitando a clonagem de um novo repositório descoberto deles também.

Isso acontece não apenas quando eu começo com um arquivo corrompido no repositório nu, mas também é possível introduzir um arquivo corrompido de um repositório de trabalho em um repositório simples dessa forma.

Claro, pode-se consertar isso por outros meios, mas ainda estou surpreso (e um pouco preocupado) com a facilidade que parece ser bagunçar o repositório para todos que trabalham com ele. Especialmente desde que o erro pode permanecer despercebido até a próxima vez que alguém tentar clonar. Não deveria haver verificações contra isso, em algum lugar, de alguma forma?

Alguém aqui disposto a tentar se é reproduzível? Eu experimentei com a versão 2.7.4 do git.

Qualquer conselho sobre como verificar essa corrupção é muito bem-vindo.

Respostas:


1

Eu estava realmente assumindo que algo vai quebrar no próximo push ou pull, mas para minha surpresa, tudo parecia funcionar bem. Mais se compromete, mais empurrando e puxando, sem problemas.

Cada objeto - arquivo, confirmação, etc. - é nomeado após o hash SHA1 de seu conteúdo (mais um pequeno cabeçalho). Sempre que um objeto individual é lido na memória para uso, os dados são codificados e comparados com o nome do objeto; qualquer incompatibilidade causará um erro a ser mostrado.

Contudo, a maioria das operações não precisa ler todo o repositório na memória. Em geral, todos os comandos apenas lêem o mínimo necessário - claro, você seria Notei o problema se você tentou verificar um commit ou diff quebrado, mas operações como criar um commit não se importam com objetos anteriores. Mesmo empurrando precisa de apenas uma pequena seleção de objetos (como a base delta para pacotes 'finos') porque ambos os pares sabem o que o outro lado já tem.

(Essa otimização é um resultado direto do layout baseado em instantâneo. Por exemplo, git add não precisa delta em relação aos arquivos antigos, porque ele simplesmente cria um novo instantâneo. Então git commit transforma este instantâneo em objetos de confirmação / árvore sem saber qualquer coisa sobre o commit anterior, exceto seu ID.)

Isso acontece não apenas quando eu começo com um arquivo corrompido no repositório vazio, como também é possível introduzir um arquivo corrompido de um repositório de trabalho em um repositório simples dessa maneira.

Em primeiro lugar, lembre-se de que um clone do mesmo sistema de arquivos do mesmo computador não compacta e transfere objetos - ele simplesmente vincula os arquivos para os arquivos, a fim de economizar espaço e tempo. Você tem que explicitamente excluir isso por clonagem de um file:// URL em vez de um caminho simples.

No entanto, um clone sobre SSH ou HTTPS (ou o arquivo acima: // URLs) realmente lê e grava os dados do objeto para construir o pacote de transferência, portanto, qualquer objeto corrompido que deveria fazer parte da transferência vai abortar o processo.

Se você de alguma forma conseguir empurrar um objeto corrompido para um controlo remoto servidor - com ele deslizando através da embalagem local e do desempacotamento remoto - que é um pouco incomum (especialmente após a História de 2013 git.kde.org ) e eu levantaria essa preocupação na lista de discussão do Git.

(Não se preocupe que a documentação fala sobre transfer.fsckObjects sendo desabilitado por padrão, - desativa apenas a validação da estrutura e sintaxe do objeto, não a verificação de hash.)

Não deveria haver verificações contra isso, em algum lugar, de alguma forma?

Uma verificação completa pode ser feita manualmente usando o git fsck comando. É uma boa ideia fazer um cronjob em seus repositórios 'centrais'. A verificação completa não é automatizada porque levaria uma quantidade de tempo não razoável para verificar novamente o repositório completo em cada commit / push / pull / whatever para todos, exceto os menores repositórios Git.

UMA parcial check implicitamente acontece sempre que o git decide rodar o git gc --auto processo de manutenção de fundo. Essa manutenção lê todos os objetos 'soltos' recentemente criados e os arquiva em um arquivo .pack, portanto a verificação desses objetos é feita gratuitamente. (No entanto, em vez de executar em um agendamento predefinido, ele é executado sempre que você tiver mais objetos soltos do que o limite definido.)

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.