Por Anónimo (no verificado) , 29 Abril 2026

Introducción

Un commit Git referencia cero, uno o varios commits padres. El historial entero es un grafo dirigido acíclico (DAG) de estos enlaces de padres. Los branches y tags son simplemente etiquetas en nodos de este grafo.

Anatomía de un enlace de padre

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

Un padre: historial lineal. Dos padres: un merge. Cero padres: un commit raíz. Tres o más: un merge octopus.

Recorriendo el grafo

git log --oneline --graph --all
git log --first-parent           # seguir solo primeros padres
git log --topo-order
git log --date-order

--first-parent en main es excelente para ver el "tronco" del historial sin ruido de merges laterales.

Consultas de ascendencia

git merge-base A B               # ancestro común más reciente
git merge-base --is-ancestor X Y   # exit 0 si X es ancestro de Y
git rev-list A..B --count          # commits en B que no están en A

Sintaxis de rango

  • A..B: commits alcanzables desde B pero no desde A.
  • A...B: diferencia simétrica.
  • ^A B: igual que A..B.
  • B --not A: igual que A..B.
git log main..feature
git log main...feature --left-right --oneline

El archivo commit-graph

Desde Git 2.18, Git puede escribir un archivo commit-graph que precalcula datos de ascendencia para repos enormes:

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

Esto acelera dramáticamente git log --graph, git merge-base y verificaciones de alcanzabilidad.

Merges octopus

Un solo merge commit puede tener muchos padres:

git merge feature1 feature2 feature3

Los merges octopus solo tienen éxito sin conflictos. Son útiles para branches de integración en algunos flujos pero rara vez necesarios.

Visualizando el grafo

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

%p imprime los SHAs de los padres.

Números de generación

El archivo commit-graph almacena un número de generación por commit: 1 para commits raíz, max(generaciones de padres) + 1 de lo contrario. Los números de generación convierten muchas consultas de ascendencia en operaciones O(log n). Git moderno (2.27+) escribe fechas de commit corregidas y números de generación v2 cuando el commit-graph está habilitado:

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 adicionalmente registra un filtro Bloom por commit listando los paths cambiados, acelerando dramáticamente las consultas de git log limitadas por ruta.

Errores comunes

Imaginar los branches como pilas separadas de commits; son etiquetas en nodos que pueden compartir ancestros. Usar HEAD~3 en un merge commit y sorprenderse: ~ siempre sigue al primer padre. Usa ^2, ^3 para saltar a otros padres. Olvidar que rebase reescribe la topología del grafo creando nuevos commits con nuevos punteros padre; los commits viejos viven en el reflog. Finalmente, pensar que el grafo de commits almacena diffs; almacena trees y padres solamente. Los diffs se calculan bajo demanda comparando trees.