Depois de algum tempo usando o Git, você sabe certamente quais as melhores maneiras de usá-lo todos os dias, incluindo os comandos mais úteis.

Quando você atinge esse nível de compreensão de como usar uma ferramenta, é hora de se aprofundar em seus conceitos, arquitetura e estrutura.

Neste post, vamos entender como o Git organiza suas informações e como ele persiste essas informações em sua estrutura de arquivos.

O HEAD em .git/HEAD

HEAD é um arquivo que contém o nome da ramificação atual (current branch).

ref: refs/heads/dev

Neste exemplo, seu HEAD está apontando agora para branch dev.

HEAD também pode ser um ID de commit, que é chamado de estado HEAD desanexado (detached HEAD state).

12836deb078b57c1e800058d2cf8eb075ea24cb1

Branches em .git/refs/heads/

Cada ramificação é armazenada como um arquivo que contém 1 (apenas um) commit ID.

Esses arquivos são armazenados em uma pasta chamada refs/heads.

pasta refs/heads

Na imagem, cada arquivo é o nome de uma ramificação, e as pastas representam nomes de branches com um separador /, como fix/BUG-123. Neste exemplo BUG-123 será um arquivo com esse nome e talvez a seguinte ID de commit:

82e5b05312cc6c7af6b8fea1e09ca2f438ddd703

Tags, stash, remotes tudo em .git/refs

Assim como as branches vivem em .git/refs, também tags, `stash, remotes.

- .git
-- refs
--- heads <- *branches*
--- remotes
--- stash
--- tags

Commits em .git/objects

Um commit é salvo em um arquivo contendo seu(s) pai(s) (parents), mensagem, árvore e autor.

Essas informações são compactadas e a melhor maneira de ver objetos git é usando o comando:

git cat-file -p HASH

No comando acima, HASH é a ID de commit.

git cat-file -p 95173d8501

# output
tree e0645455629c2bd9d64b81fb17503dcb4df5bd9f
parent 81b21476b2c5d19a8fdbf9d414b42088c94484c8
parent 7473e3c226411ed5252539ca9d337de0a6f9ccbb
author Ademir Mazer Jr [ Nuno ] <[email protected]> 1697586900 -0300
committer GitHub <[email protected]> 1697586900 -0300
gpgsig -----BEGIN PGP SIGNATURE-----
 
 XXXXXABCAAQBQJlLx7UCRBK7hj4Ov3rIwAAwREIAJynSGsjhJnjaLpYbEF/fp7O
 VZQ8o+ZS+Pg/F4tG8ytE4Yd4B9hp63pwrpaDIJx27SARzOokIKovie99pQrVMfUz
 DQviwVd41Eh6aNqkDcj0qNihw15rM/EZqUTUW6ApMgg/8kdtcsdsdsd
 5FWRzG43Q98ZgvZQJfzPeAmePKap/iGZNfsg0LMLB6vBQ1xVXyQ6lY8scDPv2lg3
 HDeldfJqsjEDzDODbcv2GcyhkOmb32Esn7R5H5bjgXaCqAWZI+40HgxTwfRratlNsdsdsdssdCI9TPHwFGHfW4Lk3t/9HIx7ldWRtoEykOVL01Ak=
 =QWAS
 -----END PGP SIGNATURE-----
 

Merge pull request #705 from Mazer/1510-planilha-prod-preco

fix: staus de completo da classe quando não tem um item na NF do pedido

Árvores (trees) em .git/objects

Árvores são arquivos com listagens de diretórios. Os arquivos nele são chamados de blobs.

git cat-file -p master^{tree}

# output
100644 blob 6537ca4677ee97ddcb112f22d086b92721fd578c	.editorconfig
100644 blob 354be23c7b01803db48f6008a82ce042e41f9a04	.env.example
100644 blob 967315dd3d16d50942fa7abd383dfb95ec685491	.gitattributes
100644 blob f6fb8a7f6d07dd3f7a624bb373f87be0365cc569	.gitignore
100644 blob 57f7d3b20c41447e1c9f6cc80fd161b9cad54d42	.rnd
040000 tree 42f824c3c2b6743a468d08893b3fdaa453316fc5	.scribe
100644 blob 9231873a112ba0ded2550a45741bad544e7a1998	.styleci.yml
040000 tree e7170f21fba71d487011969e6eebae029cbc2afd	.vscode
100644 blob 80258098b18a85ff17ccf7d29259886882ee97be	README.md
040000 tree e489d9339d4dfd9c025a40053c18815596d1df08	app
100644 blob 5c23e2e24fc5d9e8224d7357dbb583c83884582b	artisan
040000 tree fa579600b150dfe96277f923c509bc473517b32a	bootstrap
100644 blob 08183152f2089d6c229474c8eb020fd54fe0070c	composer.json
100644 blob 67772e4ece555d51d3833d5f1b8c634902ceb709	composer.lock
040000 tree bf28bd62dc2e4604e853c6aac64b4ee6bb79c762	config
040000 tree 48955a5c0935bcb7c88b1cbb0599eba405b66b36	database
100644 blob 769dd5516e2308eff567d1774de12a842db7f16b	package-lock.json
100644 blob ca5629bc4cd598cae98b89c723a707b3f7bc6b38	package.json
100644 blob 90952f05a7c49f0ebc6af0fe4f7b332cd61ea586	phpstan.neon
100644 blob 4ae4d979d1ecc9bb45aabf0ff7071ce0e63bd4e2	phpunit.xml
040000 tree 2297374bcd5c5d552865315e4d310cc14de468d7	public
040000 tree a6ef03f417eff40e2e6a1e19ff020a789c2dc201	resources
040000 tree 33d6539ee1ae71d17961971a618825157083e38a	routes
100644 blob 5fb6379e71f275a1784e6638adc96420aaa5c5b2	server.php
040000 tree d0be5083619e6e92c3408f2455afd9b338970e16	storage
040000 tree d50aa6e9b745b0dba78abd8fa5b1c9a57946a46a	tests
100644 blob b9889e995f67106aebdb994d29c30e4dd5a85325	webhook-deploy.sh
100644 blob 6189710be60e7cb518dc9f5e7eea7d4b88879388	webpack.mix.j

Blobs em .git/objects

Blobs são os arquivos que contêm seu conteúdo real (código-fonte, textos, etc).

git cat-file -p 6537 

# output
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.md]
trim_trailing_whitespace = false

[*.{yml,yaml}]
indent_size = 2

Observe a primeira linha da seção anterior (Árvores), 6537 é o código hash do arquivo blob para .editorconfig.

Reflog em .git/logs/refs/heads/main

reflog armazena o histórico de cada branch, tag e HEAD na pasta .git/logs/refs. Nesse diretório, o arquivo HEAD armazena o log HEAD completo. Em subdiretórios dentro de refs há história de logs para heads e remotes.

Cada linha de reflog tem:

  • antes/depois de commit IDs
  • usuário
  • carimbo de data/hora
  • mensagem de log
0000 6e6b Ademir Mazer Junior <[email protected]> 1695844143 -0300	branch: Created from HEAD
6e6b 075d Ademir Mazer Junior <[email protected]> 1695847428 -0300	commit: feat: #1510 planilha modelo com produtos
075d af8b Ademir Mazer Junior <[email protected]> 1697505509 -0300	commit: fix: corrige atualização de preço promocional pela planilha
af8b ff78 Ademir Mazer Junior <[email protected]> 1697544622 -0300	commit: fix: nome da classe
ff78 7473 Ademir Mazer Junior <[email protected]> 1697586865 -0300	commit: fix: staus de completo da classe quando não tem um item na NF do pedido
7473 44a1 Ademir Mazer Junior <[email protected]> 1698783202 -0300	commit: fix: cálculo de valor final e exception no cálculo de valor promocional

Rastreamento branches remotas em .git/refs/remotes/origin/main

Os rastreamentos-remotos de branches armazenam a ID de commit existente mais recentemente para uma branch remota.

Quando o git status mostra you're up to date with origin/main (que você está atualizado com origin/main), ele está se referindo ao ID de commit no arquivo main dentro de refs/remotes/origin.

59be37277161007fccab827ad3e4196563216eb6

Configuração em .git/config

A configuração do repositório é armazenada no arquivo .git/config. Nesse arquivo, você define remotes, autor e outras configurações de repositório.

O Git tem configurações locais, globais e do sistema. As configurações globais geralmente estão localizadas em ~/.gitconfig.

Para saber mais sobre configurações, leia Git Config: Configuração de Email e Username.

Níveis de configuração do Git
Git config levels
.

Hooks em .git/hooks/pre-commit

Os scripts chamados hooks no Git são opcionais, você pode escrever scripts para fazerem qualquer coisa, configurar e executar quando algum evento ocorrer no fluxo de trabalho do Git, por exemplo antes de um commit.

#!/bin/bash
phpstan app/

Área de staging em .git/index

A área de staging armazena arquivos que estão prontos para serem confirmados (commited). O arquivo onde eles são armazenados é um arquivo binário chamado index.

Para saber mais sobre o git index leia: Git Index.

Considerações Finais

Para engenheiros de software e desenvolvedores, uma compreensão profunda dos arquivos e da estrutura de pastas do Git não apenas aumenta a proficiência no uso do Git, mas também capacita a solucionar problemas, otimizar e aproveitar o Git em todo o seu potencial.