A anatomia de um commit no git

Lilian Lima
3 min readJun 10, 2019

Você já reparou que ao gerar um commit no git você recebe um identificador único com 40 posições? Esse identificador na verdade é um código hash SHA-1 gerado por um algoritmo a partir de uma porção de dados.

E que porção de dados é essa considerada na geração do hash?

Existem 4 tipos de objetos que são armazenados no git: commit objects, annotaded tag objects, blobs and tree objects, para iniciar o detalhamento desses objetos considere a seguinte estrutura de arquivos:

Fig. 2 — Estrutura de arquivos

Cada arquivo no git é armazenado como um objeto blob, por exemplo, a partir do conteúdo do arquivo logo.png ele gera um hash que será armazenado em algum lugar endereçável como aa1b2fb696a831c89c53f787e03d863691d2b671 . O mesmo ocorre com o arquivo app.css que é armazenado em 4c511f16ef2644854d04cabebfcecc82be0eb04f e assim também acontece com o arquivo app.js. Ótimo, e como o git relaciona o arquivo logo.png com o hash aa1b2fb696a831c89c53f787e03d863691d2b671?

Os arquivos logo.png e app.css estão no mesmo diretório assets, e este diretório é representado como um tree object, ele trabalha como um mapa, ele relaciona o nome do arquivo ao hash gerado a partir de seu conteúdo, como exemplificado abaixo:

Fig 3 — Tree object (mapeamento do nome do arquivo X hash)

Atrás de um hash pode existir um simples arquivo, armazenado como blob, ou outro tree object, como nessa representação “gitiana” da estrutura de arquivos completa:

Fig. 4 — Snapshot do working directory

A pasta assets e o arquivo app.js estão no mesmo diretório e num nível superior aos arquivos logo.png e app.css, e novamente o mapeamento é aplicado fazendo a associação do nome asset (diretório) ao hash 7cf2a17f3345635d59e063cffddd23573b6e4a75, repare que aqui o conteúdo não é de um arquivo, mas de um tree object filho, pois ele está debaixo do diretório raiz “.” . E o arquivo app.js é associado ao hash 29bfcf9fa5824331081b31f0c307806c6f6b6f06. E, se subirmos ao topo da estrutura veremos que o diretório raiz também está associado a um hash, 9c435a86e664be00db0d973e981425e4a3ef3f8d.

Quando você executa o comando git add o git bate uma foto (snapshot) do working directory e a armazena em sua memória interna, quando você executar o comando git commit o seguinte objeto de commit num pseudo código será gerado:

sha1(
commit message => feature commit”
committer => Lilian Lima <lilian.lima@mail.com>
commit date => Sat Jun 8 09:15:59 2019 +0100
author => Lilian Lima <lilian.lima@mail.com>
author date => Sat Jun 8 09:15:59 2019 +0100
tree => 508222e4b5ba555711173ff140a6263bef867166
parents => [d0957cc8c91520eedcd3807baa96170020812f0e]
)

Só reforçando, o objeto de commit é composto pelo metadata do commit+ tree object (snapshot do working directory) + identificador do commit antecessor/ancestral/pai

E adivinhem o que o git faz com esse objeto de commit?!? Gera um hash dele também e é esse identificador que visualizamos ao executarmos um git log.

O git utiliza essa abordagem de criptografia para assegurar a integridade dos commits, caso um bit seja alterado no commit realizado, mesmo que seja um espaço em branco num arquivo, um novo identificador será gerado.

Esse post é quase uma transcrição desse outro post: https://blog.thoughtram.io/git/2014/11/18/the-anatomy-of-a-git-commit.html

Lilian Lima

--

--