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

Assim, inicialmente x e y estão empurrando e puxando de x.git e tudo funciona bem. Agora, digamos que um dos objetos de metadados ( .git/objects/... ) em x.git seja corrompido por qualquer motivo (escolha 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, porque graças à arquitetura do git, eu posso simplesmente despejar o repositório nu no pior dos casos, e recriá-lo com todo o histórico de um dos meus conjuntos de trabalho. Mas não. Sem qualquer aviso prévio, o arquivo corrompido foi acessando os repositórios de trabalho, tornando impossível clonar um novo repositório descoberto deles também.

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 de uma forma simples.

Claro, pode ser possível 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 controlar essa corrupção é muito bem-vindo.

    
por Wanderer 28.09.2018 / 15:11

1 resposta

1

I was actually assuming that something will break at the next push or pull, but to my surprise, everything appeared to work fine. More commits, more pushing and pulling, no problems.

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

No entanto, a maioria das operações não precisa para ler todo o repositório na memória. Em geral, todos os comandos apenas lêem o mínimo necessário - claro, você teria notado o problema se você tentasse 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, o git commit transforma este instantâneo em objetos commit / tree sem conhecer qualquer coisa sobre o commit anterior, exceto seu ID.

This happens not only when I start with a corrupted file in the bare repository, it is also possible to introduce a corrupted file from a working repository in a bare one this way.

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 desativar isso clonando a partir de uma URL file:// 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 criar o pacote de transferência, portanto, qualquer objeto corrompido que deveria fazer parte da transferência irá abortar o processo.

Se você, de alguma forma, conseguir empurrar um objeto corrompido para um servidor remoto - deslizando através do empacotamento local e da descompactação remota - isso é um pouco incomum (especialmente após o 2013 história do git.kde.org ) e eu levantaria essa preocupação na lista de discussão do Git.

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

Shouldn't there be checks against this, somewhere, somehow?

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

Uma verificação parcial acontece implicitamente sempre que o git decide executar o processo de manutenção em segundo plano git gc --auto . 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.)

    
por 28.09.2018 / 16:07