W3docs

git reflog

Información detallada sobre el comando git reflog: referencias, subcomandos, reflogs con marca de tiempo y ejemplos para recuperar commits perdidos.

El comando git reflog es tu red de seguridad. Registra cada cambio realizado en las referencias locales — ramas, HEAD y stashes — para que puedas recuperar commits que parecen haber desaparecido tras un reset, rebase, amend o una rama eliminada. Esta página explica qué almacena el reflog, cómo leer su sintaxis name@{n}, cómo filtrar entradas por tiempo, los subcomandos disponibles y un recorrido completo para recuperar commits "perdidos".

Qué es el reflog

Una referencia (o "ref") es un puntero a un commit — HEAD, la punta de una rama como main, o una entrada de stash. Muchas operaciones de Git mueven estos punteros: cada git commit, checkout, merge, rebase o reset actualiza a dónde apunta una ref. El reflog ("registro de referencias") almacena ese historial de movimientos.

Esto importa porque Git casi nunca elimina commits de inmediato. Cuando una operación como un hard reset o un rebase hace que un commit sea inalcanzable desde cualquier rama o etiqueta, el objeto commit sigue viviendo en tu repositorio y el reflog todavía guarda un puntero hacia él. Mientras esa entrada del reflog exista, puedes recuperar el commit.

git reflog

Información

El reflog es estrictamente local y por clon. Nunca se envía ni se recibe con push/fetch, por lo que un clon recién creado tiene un reflog vacío. Si reescribes el historial y pierdes un commit, solo puedes recuperarlo desde la máquina donde se realizó el trabajo.

Uso básico

La forma más simple no requiere argumentos:

git reflog

Es un atajo para mostrar el reflog de HEAD:

git reflog show HEAD

La salida muestra cada posición que ha ocupado HEAD, la más reciente primero:

a32556a HEAD@{0}: commit: migrating content
ab371fd HEAD@{1}: commit: adding git reflog outline
23a491a HEAD@{2}: checkout: moving from stage to feature/solver
7b119cb HEAD@{3}: checkout: moving from feature/solver to stage
56a183a HEAD@{4}: commit: changing color scheme
7a2aa71 HEAD@{5}: commit: adding more color palettes
a56322b HEAD@{6}: commit: adding color tool package

Lee cada línea como tres partes:

  • a32556a — el hash abreviado del commit al que apuntaba HEAD.
  • HEAD@{0} — el selector del reflog. @{0} es la posición más reciente, @{1} la anterior, y así sucesivamente, contando hacia atrás en el tiempo.
  • commit: migrating content — la acción que movió la ref, más su mensaje.

La etiqueta de acción indica cómo se movió la ref (commit, checkout, merge, rebase -i, reset), lo que hace que el reflog sea legible como un historial paso a paso de lo que hiciste localmente.

Referencias del reflog

Por defecto git reflog muestra el reflog de HEAD, que sigue a la rama que esté actualmente activa. Pero cada ref mantiene su propio reflog, y puedes acceder a cualquiera de ellos con la sintaxis name@{qualifier}.

Para ver el reflog de todas las referencias a la vez:

git reflog show --all

Pasa el nombre de una rama para inspeccionar solo el historial de esa rama. A continuación, el reflog de test_branch:

git reflog show test_branch
32a591f test_branch@{0}: commit: add snippets
23bae4a test_branch@{1}: commit (initial): initial commit

Nota la diferencia: HEAD@{1} significa "dónde estaba HEAD hace un movimiento", mientras que test_branch@{1} significa "dónde estaba test_branch en sí hace un movimiento". Esta distinción es la que permite recuperar la punta de una rama que un hard reset o una actualización forzada desplazó.

También puedes leer el reflog del git stash:

git reflog stash
0d44de3 stash@{0}: WIP on git_reflog: a567574 adding Vue.js

Reflogs con marca de tiempo

Cada entrada del reflog tiene una marca de tiempo asociada. Estas se pueden usar como calificadores en la sintaxis de puntero de ref de Git, lo que permite filtrar los reflogs por tiempo. Aquí hay algunos ejemplos de calificadores de tiempo:

  • 1.minute.ago
  • 1.hour.ago
  • 1.day.ago
  • yesterday
  • 1.week.ago
  • 1.month.ago
  • 1.year.ago
  • 2011-05-17.09:00:00

Puedes combinar calificadores (p. ej. 1.week.3.hours.ago) y usar formas en plural (p. ej. 5.hours.ago). Una ref con calificador de tiempo puede pasarse a otros comandos de Git, no solo a git reflog:

git diff master@{0} master@{1.week.ago}

Esto muestra las diferencias entre el master actual y dónde apuntaba master hace una semana.

Advertencia

Un calificador de tiempo se resuelve contra el reflog, no contra las fechas de los commits. master@{1.week.ago} significa "el commit al que hacía referencia master hace una semana en esta máquina", lo cual puede diferir de "el commit creado hace una semana". En un clon reciente sin historial de reflog, Git recurrirá a la punta actual y puede advertir que el registro es demasiado corto.

Subcomandos de git reflog

Git reflog acepta varios argumentos que actúan como subcomandos. Se describen a continuación.

git reflog show

git reflog show es el comportamiento predeterminado y es en sí mismo un alias de git log -g --abbrev-commit --pretty=oneline. Estos dos comandos son equivalentes:

git reflog master@{0}
git reflog show master@{0}

git reflog expire

git reflog expire elimina entradas antiguas o inalcanzables del reflog. Dado que eliminar entradas puede hacer que los commits sean genuinamente irrecuperables, rara vez se ejecuta manualmente — Git lo ejecuta automáticamente durante git gc. Por defecto, las entradas alcanzables expiran después de 90 días (gc.reflogExpire) y las inalcanzables después de 30 días (gc.reflogExpireUnreachable). Para forzar una expiración personalizada:

git reflog expire --expire=1.day.ago --all

git reflog delete

git reflog delete elimina una entrada específica del reflog por su selector. Al igual que expire, conlleva un riesgo real de perder la recuperabilidad y rara vez se necesita en el trabajo diario:

git reflog delete HEAD@{1}
Peligro

Una vez que una entrada del reflog expira o se elimina, el commit al que apuntaba se vuelve verdaderamente inalcanzable y será eliminado la próxima vez que se ejecute git gc. Considera expire y delete como herramientas de limpieza, no de deshacer.

Recuperar commits perdidos

Los commits nunca se pierden verdaderamente en Git, incluso durante operaciones de reescritura de historial — y el reflog es la forma de recuperarlos. Supongamos que git log --pretty=oneline muestra esto:

2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

Ahora supongamos que hacemos commit de algunos cambios nuevos en este repositorio:

# make changes to HEAD
git commit -am "API changes"

El log ahora tiene este aspecto:

37656e19d4e4f1a9b419f57850c8f1974f871b07 API changes
2b43ceab309da94256db8fb1f35b1678fb74abd4 changes in content
c32557493a95185997c87e0bc3a9481715279351 adding Vue.js
abc234f986d270d7f97c77618314a06f024c4563 migrating content
a5673cd762d8ef2e146d7f0226e81a92f91956b1 adding git reflog outline
2bce4a4404c42128bee8468a9517418ed0ea412 initial commit

A continuación iniciamos un rebase interactivo contra master:

git rebase -i origin/master

Durante el rebase marcamos commits con la acción s (squash) para fusionarlos en el commit "API changes" más reciente. Después, la salida de git log queda reducida a:

40d8a1237656e19d4e4f1a9b419f57850c8f1974 API changes
35aee4a4404c42128bee8468a9517418ed0eb3dc initial commit

Los commits combinados con squash parecen haber desaparecido. Pero el reflog sigue registrando cada posición que ocupó HEAD durante el rebase:

git reflog
37656e1 HEAD@{0}: rebase -i (finish): returning to refs/heads/git_reflog
37656e1 HEAD@{1}: rebase -i (start): checkout origin/master
37656e1 HEAD@{2}: commit: API changes

HEAD@{2} es el estado justo antes de que comenzara el rebase. Pasa ese selector a git reset para retroceder a él:

git reset --hard HEAD@{2}

Esto mueve HEAD de vuelta al commit "API changes" previo al rebase y restaura todos los commits combinados. Usa --hard para restablecer también tu árbol de trabajo a ese estado, u omítelo (git reset HEAD@{2}) para mover solo el puntero de la rama manteniendo los archivos actuales.

Cuándo usar git reflog

Recurre al reflog siempre que una ref se haya movido y quieras recuperarla:

  • Después de un git reset --hard que descartó commits que realmente necesitabas.
  • Para recuperar commits huérfanos por un rebase interactivo, amend o squash.
  • Para restaurar una rama que eliminaste con git branch -D (encuentra su última punta en el reflog y luego ejecuta git branch <name> <hash>).
  • Para encontrar dónde estaba HEAD antes de una serie confusa de checkouts o merges.

Si el commit es más reciente que la ventana de expiración del reflog (90 días para las entradas alcanzables por defecto), es recuperable.

Páginas relacionadas

  • git reset — mueve refs a una entrada del reflog para deshacer cambios.
  • git rebase — la operación de reescritura que el reflog rescata con más frecuencia.
  • git stash — los stashes tienen su propio reflog bajo stash@{n}.
  • git log — la vista del historial habitual; git log -g lee el reflog.

Práctica

Práctica
¿Cuáles son las afirmaciones correctas sobre el comando `git reflog`?
¿Cuáles son las afirmaciones correctas sobre el comando `git reflog`?
Was this page helpful?