Skip to main content
  1. Concetti/

Git Objects - struttura interna di git

·4 mins
Alessio Barnini
Author
Alessio Barnini
Table of Contents

Cosa fa
#

Git memorizza tutti i dati come oggetti immutabili nel database .git/objects/. Ogni oggetto e' identificato da un hash SHA-1 del suo contenuto. Una volta che un oggetto esiste nel database, non sparisce mai — anche se rimuovi un file o cancelli un commit, l'oggetto rimane fino al garbage collection.

TL;DR
#

Quando fai git commit:

  file.txt (contenuto)
  blob object          ← il contenuto del file
  tree object          ← la struttura della directory
  commit object        ← punta al tree + metadati (autore, data, messaggio)
  .git/objects/ab/cd1234...  ← tutti e tre salvati come file

Se rimuovi file.txt e fai un nuovo commit:
  il blob del vecchio file.txt RIMANE in .git/objects
  e' raggiungibile dalla storia del repo

I quattro tipi di oggetti
#

1. Blob — contenuto di un file
#

git cat-file -t abc123   # mostra il tipo → blob
git cat-file -p abc123   # mostra il contenuto del file

Un blob e' il contenuto puro di un file — senza nome, senza path. Due file identici condividono lo stesso blob.

2. Tree — struttura di una directory
#

git cat-file -p HEAD^{tree}   # albero del commit corrente
# 100644 blob abc123   README.md
# 100644 blob def456   key.txt
# 040000 tree ghi789   src/

Un tree associa nomi di file ai blob e ai subtree.

3. Commit — snapshot con metadati
#

git cat-file -p HEAD
# tree abc123def456...
# parent xyz789...
# author Nome <email> 1234567890 +0000
# committer Nome <email> 1234567890 +0000
#
# messaggio del commit

Un commit punta a un tree (lo snapshot), al commit padre, e contiene i metadati.

4. Tag — puntatore con nome
#

git cat-file -p v1.0   # tag annotato
# object abc123...
# type commit
# tag v1.0
# tagger Nome <email>
#
# Release version 1.0

Un tag leggero e' solo un riferimento a un hash. Un tag annotato e' un oggetto vero con metadati. In Bandit 30 il tag puntava direttamente a un blob — caso insolito ma possibile.


Dove vivono gli oggetti
#

.git/
├── objects/
│   ├── ab/
│   │   └── cd1234...   ← primi 2 char = directory, resto = filename
│   ├── pack/
│   │   ├── pack-xxx.pack   ← oggetti compressi insieme
│   │   └── pack-xxx.idx    ← indice del pack
│   └── info/
├── refs/
│   ├── heads/
│   │   ├── master      ← punta all'ultimo commit di master
│   │   └── dev         ← punta all'ultimo commit di dev
│   └── tags/
│       └── secret      ← punta a un oggetto tag o blob
└── HEAD                ← punta al branch corrente

Perche' i segreti sopravvivono
#

Commit A: README.md contiene "password: abc123"
Commit B: README.md aggiornato → "password: xxxxxxxxxx"
stato attuale: "password: xxxxxxxxxx"

Il commit A esiste ancora in .git/objects. E' raggiungibile con:

git log --all -p | grep -i "password"
git diff <hash-commit-A> <hash-commit-B>
git show <hash-commit-A>:README.md

L'unico modo per rimuovere un segreto dalla storia e' riscrivere la storia con git filter-branch o git filter-repo — e anche in quel caso, chiunque abbia clonato il repo prima ha ancora la versione con il segreto.


I quattro posti dove nascondersi in git
#

PostoComando per trovareLivello Bandit
Storia commitgit log -p28
Branch nascostigit branch -a29
Taggit tag + git show30
Stashgit stash list

Pack files
#

Quando un repository cresce, git comprime gli oggetti in pack files:

ls .git/objects/pack/
# pack-abc123.pack   ← oggetti compressi
# pack-abc123.idx    ← indice per trovare gli oggetti nel pack

# Estrarre il contenuto di un pack (per analisi forense)
git verify-pack -v .git/objects/pack/pack-abc123.idx

I pack files contengono tutti gli oggetti storici — inclusi quelli di branch cancellati e commit rimossi con git reset.


Scenario Reale
#

Un developer commette per errore una chiave API in un commit, se ne accorge e la rimuove nel commit successivo. La chiave e' ancora accessibile:

# Trovare la chiave nella storia
git log --all -p | grep -i "api_key\|secret\|password\|token"

# Verificare quando e' stata aggiunta e rimossa
git log --all --oneline | head -20

# Leggere il file com'era in quel commit
git show abc123:config.py

Strumenti professionali che fanno questo automaticamente: truffleHog, git-secrets, gitleaks. GitHub ha un sistema integrato che notifica automaticamente quando trova pattern di chiavi note (AWS, GCP, Stripe...) nei push.


Dove l'ho incontrato
#

  • bandit-28 — secret scanning nella storia dei commit
  • bandit-29 — branch nascosti con credenziali
  • bandit-30 — tag che puntano a blob con password
  • bandit-31 — .gitignore bypass per push

Collegato a
#

  • system — categoria
  • incidents — categoria
  • git — comando
  • secret-scanning — applicazione pratica
  • bandit-28 — primo secret scanning

Related