Además del grafo de commits en sí, cada repositorio local mantiene
un reflog: un registro cronológico de cada posición por la que
pasó HEAD (y, por separado, cada rama), sin importar si esos
commits siguen siendo alcanzables desde alguna rama actual.
git reflog
Esto muestra algo como:
a1b2c3d HEAD@{0}: commit: Corrige el cálculo de totales
e4f5g6h HEAD@{1}: reset: moving to HEAD~2
i7j8k9l HEAD@{2}: commit: Agrega validación
Este es el motivo por el que operaciones como reset --hard o
commit --amend rara vez causan pérdida de datos real, aunque
lo parezcan: mientras el reflog conserve la entrada, el commit
todavía existe en la base de datos de objetos y puede recuperarse.
git reset --hard HEAD@{2}
o, de forma equivalente, apuntando una rama nueva directamente al commit recuperado:
git branch recuperada HEAD@{2}
El reflog es local: no se transmite con push ni con
clone, y cada copia del repositorio tiene el suyo propio. Las
entradas también expiran con el tiempo (por defecto, 90 días para
las alcanzables y 30 para las que ya no lo son), tras lo cual
git gc puede eliminar definitivamente los objetos que ya
nadie referencia. Por eso el reflog es una red de seguridad para
errores recientes, no un archivo histórico permanente.