Desenvolvimento

25 set, 2012

Dica Git da semana: Git BigJobbies

Publicidade

Esta dica abrange dois aspectos: em primeiro lugar, é um meio de mostrar como Git pode ser facilmente estendido, e em segundo, uma forma de mostrar que o suporte a grandes arquivos Mercurial pode ser implementado de uma forma relativamente fácil no Git. É importante notar que git bigjobbies não se destina ao uso em produção, e sim como uma experiência de aprendizagem.

Recap de armazenamento de objetos

O banco de dados do git armazena um conjunto de objetos via hash. Esses objetos podem apontar para um dos objetos, trees ou commits. Em última análise, um branch (ou tag) no Git é apenas um ponteiro para um commit, que aponta para o commit anterior e para uma tree; as trees, por sua vez, apontam para um gráfico recursivo de trees e blobs.

Como resultado, você pode furar colocar qualquer coisa que desejar em um repositório Git, desde que seja inserido no banco de dados objeto de hash. Além disso, quando você fizer clone/fetch/pull em um repositório Git, você não obtém, necessariamente, tudo o que o repositório contém; em vez disso, você obtém todos os commit alcançáveis (e, portanto, transitivamente, trees alcançáveis e blobs) para aqueles que você não tiver ainda. (No caso de um clone, o conjunto de coisas que você tem é o conjunto vazio que torna o cálculo trivial.).

No entanto, quando faz um clone, você não obtém os objetos que não estão ao alcance. Por isso, experiências fracassadas sugerem alterações que não foram aceitas em um fluxo de trabalho Gerrit (ou retrabalhadas para fornecer uma implementação diferente), ou apenas branches ou offshoots nos quais você não está interessado, não são baixados quando você faz um clone um repositório. (Commits que são ancestrais diretamente são naturalmente derrubados; apenas as partes divergentes não são baixadas.).

Objetos inacessíveis são finalmente capturados pelo coletor. Ao trabalhar a partir de listas conhecidas de raízes (por exemplo, tags, branches) o git  gc pode trabalhar quais objetos não estão mais acessíveis a partir de qualquer referência, e, finalmente, podá-los a partir do registro.

Podemos usar o banco de dados do objeto a nosso favor, para armazenar dados de objetos externos em um repositório que não for acessível a partir do branch, mas ainda for referenciado em refs e, assim, que pode ser resolvido a partir do sistema de controle de versão centralizado descentralizado. Enter:

Git Bigjobbies

O Git Bigjobbies é uma extensão que criei para demonstrar objetos externos que estão sendo armazenados em um repositório Git. Note que ele não é suportado nem recomendado. Mas o que ele faz e como funciona?

(master) $ touch empty
(master) $ git bigjobbies add empty
(master) $ git status
# On branch master
# Untracked files:
#   (use "git add <file>…" to include in what will be committed)
#
#    .bigjobbies
#    .gitignore
nothing added to commit but untracked files present (use "git add" to track)
(master) $ cat .bigjobbies
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 empty
(master) $ cat .gitignore
empty

A extensão escreve o objeto no banco de dados com o git hash-object -w, então o concatena em um arquivo .bigjobbies. Embora o objeto não esteja na tree ou seja referenciado por um commit, ele ainda existe no banco de dados. Como resultado, podemos resolver o conteúdo usando o hash e para o sistema de arquivos que são registrados no arquivo .bigjobbies. Desde que seja feito um commit no branch, podemos resolver o arquivo usando o hash sozinho.

Mas como nós impedimos o objeto de ser coletado pelo garbage collector quando ele não estiver disponível? Através do diretório geral refs/. Se um objeto for referenciado a partir de um arquivo refs/, ele será visto como em uso e, portanto, não será coletado pelo garbage collector.

Para escrevermos um ref, só precisamos fazer um echo no hash para um arquivo no diretório refs. Não importa como se chama – para simplificar, escreva o valor de hash como o nome. Para separá-lo de tags git e branches comuns, usamos refs/bigjobbies/e59de..391 como o nome.

Agora, quando encontramos os objetos, temos o conteúdo a partir do hash no armazenamento local (se existir) e, se não, nós encontramos por meio da referência remota origin refs/bigjobbies/369de..391. Assim como acontece com a extensão largefiles Mercurial, ele não faz o download do conteúdo dos arquivos, a menos que seja necessário. Porém existe o lado negativo: ele não precisa que os arquivos sejam baixados antes do tempo, a fim de trabalhar offline.

Vejamos como seria trabalhar em um clone:

$ cd /tmp
$ git clone /tmp/example other
Cloning into other...
done.
$ cd other
(master) $ ls -a1
(master) $ ls -a1
.
..
.bigjobbies
.git
.gitignore
(master) $ cat .git/refs/bigjobbies/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
cat: .git/refs/bigjobbies/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391: No such file or directory
(master) $ git bigjobbies resolve
(master) $ ls -a1
.
..
.bigjobbies
.git
.gitignore
empty
(master) $ cat .git/refs/bigjobbies/e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
e69de29bb2d1d6434b8b29ae775ad8c2e48c5391

O comando resolve trouxe dinamicamente a referência do servidor remoto e solucionou os conteúdos do arquivo no repositório local. Além disso, nenhum outro arquivo grande no commit interim será encontrado, a não ser que sejam mencionados no arquivo .bigjobbies.

Resumo

O intuito deste artigo era demonstrar o quão fácil é fazer uma extensão git. Tudo que você tem que fazer é colocar os executáveis com git-bigjobbies como prefixo e aí já pode executar com git-bigjobbies.

Além do mais, é um bom exercício para entender como o repositório Git funciona. As referências são somente ponteiros para hashes, e os objetos podem ser armazenados e referenciados por esses mesmos hashes. A partir daí, todo o Git tool suite é escrito; uma combinação de C e outra linguagem scripting (por exemplo:git-svn é amplamente escrita em Perl, e GitHub opera principalmente fora do Ruby).

Você pode fazer um clone do repositório BigJobbies.git do repositório GitHub em http://github.com/alblue/BigJobbies/. O repositório que você clona já possui alguns BigJobbies neles. Se fizer um git bigjobbies resolve em qualquer um dos pontos que tenham um arquivo .bigjobbies, você vai encontrá-los baixados. (Note que um bug de implementação depende do remote ser chamado de  origin, no caso de você fazer git clone -o other.).

***

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