Da Anonimo (non verificato) , 29 Aprile 2026

Introduzione

Un commit Git fa riferimento a zero, uno o più commit parent. L'intera storia è un grafo aciclico orientato (DAG) di questi link parent. Branch e tag sono semplicemente etichette sui nodi di questo grafo.

Anatomia di un link parent

git cat-file -p HEAD
# tree 9f1a...
# parent b2c3...
# parent d4e5...        (solo sui merge commit)
# author Ada ...
# committer Ada ...

Un parent: storia lineare. Due parent: un merge. Zero parent: un commit root. Tre o più: un merge octopus.

Percorrere il grafo

git log --oneline --graph --all
git log --first-parent           # segui solo i primi parent
git log --topo-order
git log --date-order

--first-parent su main è ottimo per vedere il "trunk" della storia senza il rumore dei lati di merge.

Query di antenati

git merge-base A B               # antenato comune più recente
git merge-base --is-ancestor X Y   # exit 0 se X è antenato di Y
git rev-list A..B --count          # commit in B non in A

Sintassi di range

  • A..B: commit raggiungibili da B ma non da A.
  • A...B: differenza simmetrica.
  • ^A B: uguale a A..B.
  • B --not A: uguale a A..B.
git log main..feature
git log main...feature --left-right --oneline

Il file commit-graph

Da Git 2.18, Git può scrivere un file commit-graph che pre-calcola dati di antenati per repo enormi:

git commit-graph write --reachable
git config --global core.commitGraph true
git config --global gc.writeCommitGraph true

Questo accelera drasticamente git log --graph, git merge-base e i controlli di raggiungibilità.

Merge octopus

Un singolo merge commit può avere molti parent:

git merge feature1 feature2 feature3

I merge octopus riescono solo senza conflitti. Sono utili per branch di integrazione in alcuni workflow ma raramente necessari.

Visualizzare il grafo

git log --oneline --graph --decorate --all
gitk --all
git log --pretty=format:'%h %p %s'

%p stampa gli SHA dei parent.

Numeri di generazione

Il file commit-graph memorizza un numero di generazione per commit: 1 per commit root, max(generazioni parent) + 1 altrimenti. I numeri di generazione trasformano molte query di antenati in operazioni O(log n). Git moderno (2.27+) scrive date di commit corrette e numeri di generazione v2 quando il commit-graph è abilitato:

git commit-graph write --reachable --changed-paths
git config gc.writeCommitGraph true
git config core.commitGraph true
git log --oneline --graph -n 5

--changed-paths registra inoltre un Bloom filter per commit che elenca i path modificati, accelerando drasticamente le query git log limitate per path.

Errori comuni

Immaginare i branch come stack separati di commit; sono etichette su nodi che possono condividere antenati. Usare HEAD~3 su un merge commit ed essere sorpresi: ~ segue sempre il primo parent. Usa ^2, ^3 per saltare ad altri parent. Dimenticare che il rebase riscrive la topologia del grafo creando nuovi commit con nuovi puntatori parent; i vecchi commit vivono nel reflog. Infine, pensare che il grafo dei commit memorizzi i diff; memorizza solo tree e parent. I diff vengono calcolati su richiesta confrontando i tree.