Back

Como o Git Funciona Por Baixo do Capô: Objetos, Árvores e Blobs

Usamos git add, git commit e git push todos os dias. Mas você já olhou dentro da pasta .git?

Entender os componentes internos do Git desmistifica a "mágica" e torna você um usuário muito mais confiante (e melhor em resolver conflitos de merge!).

Em seu núcleo, o Git é um sistema de arquivos endereçável por conteúdo. Idealmente, é um armazenamento chave-valor onde:

  • Chave: Hash SHA-1 do conteúdo.
  • Valor: O próprio conteúdo.

Vamos explorar os três objetos principais que o Git usa para armazenar seu histórico.

1. O Blob (Binary Large Object)

Quando você faz git add em um arquivo, o Git pega o conteúdo desse arquivo e o armazena como um Blob.

  • Não armazena o nome do arquivo, apenas o conteúdo.
  • Se dois arquivos tiverem exatamente o mesmo conteúdo, eles compartilham o mesmo Blob (desduplicação!).

Você pode ver isso com git cat-file:

$ echo "hello" | git hash-object -w --stdin ce013625030ba8dba906f756967f9e9ca394464a

Esse hash é a chave.

2. A Árvore (Tree)

Então, onde os nomes de arquivo são armazenados? Em um objeto Tree.

Uma Árvore é como um diretório. Contém uma lista de:

  • Permissões de arquivo (ex: 100644)
  • Tipo de objeto (blob ou tree)
  • Hash SHA-1
  • Nome do arquivo

Pense em uma Árvore como um instantâneo de uma estrutura de pastas.

100644 blob ce0136...    hello.txt
100644 blob 9a8b7c...    README.md
040000 tree 3b1c2d...    src

3. O Commit

Finalmente, temos o objeto Commit.

Um commit é simplesmente um wrapper que aponta para uma Tree específica (o instantâneo do projeto naquele momento) e adiciona metadados:

  • Autor e Committer
  • Data
  • Mensagem do Commit
  • Hash do Commit Pai

Como cada commit aponta para seu pai, eles formam uma lista encadeada (ou melhor, um Grafo Acíclico Dirigido - DAG).

tree 3b1c2d...
parent 8a9b0c...
author John Doe <[email protected]>
committer John Doe <[email protected]>

Initial commit

Visualizando a Relação

graph TD subgraph Commit C[Objeto Commit] -->|Aponta para| T[Objeto Tree] C -->|Aponta para| P[Commit Pai] end subgraph Tree T -->|Contém| B1[Blob: hello.txt] T -->|Contém| B2[Blob: README.md] T -->|Contém| T2[Tree: src] end subgraph Blob B1 -->|Conteúdo| Content1["hello"] B2 -->|Conteúdo| Content2["# Readme"] end

Juntando Tudo

Quando você executa git commit:

  1. O Git cria Blobs para os arquivos alterados.
  2. O Git cria uma Tree representando a estrutura do projeto.
  3. O Git cria um objeto Commit apontando para essa Árvore e para o commit anterior.
  4. O ponteiro da branch (ex: main) move-se para este novo hash de commit.

Por Que Isso Importa

  • Git é imutável: Uma vez que um objeto é criado, ele nunca muda. "Modificar" o histórico na verdade cria novos objetos.
  • Branching barato: Uma branch é apenas um pequeno arquivo de 40 bytes contendo um hash de commit. Criar uma branch não custa nada.
  • Integridade: O hash SHA-1 garante que se um único bit de dados mudar, o ID muda. É impossível corromper o histórico sem detecção.

Na próxima vez que você estiver preso no estado "detached HEAD", lembre-se: você está apenas apontando para um objeto Commit que não está rotulado com um nome de branch!

TechGitVCSInternals

Explore ferramentas relacionadas

Experimente estas ferramentas gratuitas do Pockit