Seções iMasters
Desenvolvimento

Dica Git da semana: Objetos

A dica desta semana Git da semana é sobre armazenamento de objetos git.

Vamos dar um mergulho mais profundo na maneira como o Git armazena seus objetos. Veremos como eles estão identificados, como eles estão relacionados, e veja por que o Git lida melhor com movimentos do que outros sistemas de controle de versão.

Até agora, você está familiarizado com o conceito de um hash de commit (ou apenas commit) – uma sequência hexadecimal de 40 caracteres, que pode identificar um change log, tais como d16085b3b913e5bc5e351c0a7461051e9973629a. Mas de onde vem isso?

Um repositório git é na verdade apenas uma coleção de objetos, cada um identificado com o seu próprio hash. Sempre que você adicionar um arquivo, você recebe um hash gerado em seu conteúdo, e esse hash é usado exclusivamente para apontar para aquela versão de um arquivo. Por exemplo, se você criar um arquivo vazio, ele terá o hash e69de29bb2d1d6434b8b29ae775ad8c2e48c5391. Você pode confirmar isso adicionando um arquivo vazio a um repositório e usando git ls-trees para ver o conteúdo:

(master) $ touch empty
(master) $ git add empty
(master) $ git commit -a -m "Empty"
[master (root-commit) 4145429] empty
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 empty
(master) $ git ls-tree master .
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 empty

O que o git ls-tree está dizendo é que o branch master contém um arquivo chamado empty, cujas permissões são 100.644 (owner read/write, group+other read), e cujo hash é e69de29bb2d1d6434b8b29ae775ad8c2e48c5391.

Da mesma forma, se você olhar no armazenamento do repositório de objetos, verá que um arquivo .git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 foi criado. O diretório é dividido de tal forma que há 256 diferentes nomes de nível superior (00-FF), e o nome do hash é concatenado com o diretório pai.

Então, como Git computa esse valor? Bem, ele usa o hash SHA1, mas o SHA1 de uma entrada vazia não é esse valor. Na verdade, o Git prefixa o objeto com “blob”, seguido do comprimento (como um número inteiro humanamente legível), por um caractere NUL, e pelo conteúdo. Então, para nosso caso, temos:

$ echo -en "blob 0\0" | shasum
$ echo -en "blob 0\0" | openssl dgst -sha1
$ printf "blob 0\0" | shasum
$ printf "blob 0\0" | openssl dgst -sha1

Tudo isso imprime o mesmo valor, e69de29bb2d1d6434b8b29ae775ad8c2e48c5391. Note que o \0 é o código de escape para o caracter NULL; o -e no echo estipula que ele deve obedecer ao escape. Se você não receber fef5d…, então está interpretando o \0 como dois caracteres, o \ e o 0. (E se você receber be21… ou b825…, então ele está adicionando uma nova linha no final.)

Em vez calcularmos esse formato, podemos usar git hash-object para calcular um hash – ou, com -w, inserir um objeto em nosso repositório local:

(master) $ echo 'Hello, World!' | git hash-object -w --stdin
8ab686eafeb1f44702738c8b0f24f2567c36da6d
(master) $ ls .git/objects/8a
b686eafeb1f44702738c8b0f24f2567c36da6d
(master) $ echo -e 'blob 14\0Hello, World!' | shasum
8ab686eafeb1f44702738c8b0f24f2567c36da6d

Isso criou um hash de nosso objeto (blob 14\0Hello World! \n) e o escreveu para o diretório objetos com o mesmo nome. Os conteúdos são comprimidos com o algoritmo Deflate, mas, no momento, ele não é usado ou mencionado em qualquer lugar em nossa árvore. Apesar de não o vermos no diretório de trabalho, podemos vê-lo no próprio repositório:

(master) $ git show 8ab686eafeb1f44702738c8b0f24f2567c36da6d
Hello, World!

Da próxima vez, vamos ver como o Git organiza objetos em diretórios e, finalmente, em commits.

?

Texto original disponível em http://alblue.bandlem.com/2011/08/git-tip-of-week-objects.html

Mensagem do anunciante:

Torne-se um Parceiro de Software Intel®. Filie-se ao Intel® Developer Zone. Intel®Developer Zone

Qual a sua opinião?