Git Reflog: Comprendiendo y Utilizando los Registros de Referencia en Git

No hay nada más molesto para un desarrollador o ingeniero de datos que borrar ramas de git o restablecer commits por accidente cuando no se quería. Por eso, estoy feliz de compartir algo que aprendí a través de mi propia experiencia y que hubiera deseado aprender antes, que es cómo usar git reflog. git reflog es una de esas técnicas que definitivamente vale la pena aprender; si inviertes un poco de tiempo ahora, puedes evitar un gran dolor de cabeza más adelante. 

Mientras te mostraré git reflog, que encuentro realmente útil para navegar y recuperarse de errores, también quiero recomendar nuestros cursos Foundations of Git e Introduction to GitHub Concepts para aprender todo lo que hay que saber sobre control de versiones.

¿Qué es git reflog?

Git reflog, o registro de referencia, es un mecanismo de seguimiento local que registra actualizaciones de las puntas de las ramas y la referencia HEAD en un repositorio de Git. (En el contexto de Git, HEAD se refiere al commit actual en el que se basan tu directorio de trabajo y área de preparación.)

A diferencia de git log, que muestra el historial de commits basado en ascendencia, mostrando cómo están conectados los commits en una rama, git reflog captura todos los movimientos de HEAD, incluyendo cambios de ramas, rebases, resets y commits. Esto hace que reflog sea útil para recuperar commits perdidos y depurar acciones recientes.

¿Cuándo se crean las entradas de reflog?

Las entradas del reflog se crean cada vez que realizas acciones que cambian el estado de HEAD o las referencias de las ramas. Escenarios comunes incluyen lo siguiente:

  • Realizar cambios con git commit.

  • Cambiar a una rama diferente con git checkout nombre_rama.

  • Crear una nueva rama con git branch nueva_rama.

  • Hacer un rebase con git rebase

  • Revertir a un commit anterior con git reset --hard.

  • Combinar ramas con git merge.

Aquí tienes el código que usas para rastrear actualizaciones en el repositorio local:

git reflog

Usando git reflog para rastrear actualizaciones en el repositorio local. Imagen por el Autor.

Cómo interpretar la salida de git reflog?

Puedes interpretar la salida de la siguiente manera:

  • HEAD@{0}: La acción más reciente fue cambiar a la rama HEAD.

  • HEAD@{1}: Antes de eso, había cambiado un archivo de tipo .xlxs a formato .csv.

  • HEAD@{2}: Hice el primer commit al enviar los archivos al repositorio.

Cada entrada muestra:

  • El hash del commit (fa82776)

  • El índice del reflog (HEAD@{0}, HEAD@{1}, etc.)

  • Una descripción de la acción realizada (commit, checkout, rebase)

Cómo usar git reflog

Git reflog proporciona una manera de rastrear actualizaciones de referencias y restaurar los estados anteriores de tu repositorio. Al comprender cómo navegar por las entradas de reflog, puedes recuperar commits perdidos, deshacer cambios y comparar versiones pasadas de tu trabajo.

Comando básico de git reflog

A continuación se muestra el comando básico de reflog:

git reflog

El comando anterior muestra una lista de acciones recientes que actualizaron HEAD o referencias de ramas, incluyendo commits, cambios de rama, resets, rebases y más. Cada entrada está indexada, como HEAD@{0} y HEAD@{1}, para representar su posición en la historia de reflog.

Referenciando estados pasados

Git reflog sirve como un registro de actualizaciones de referencias pasadas, lo que nos permite localizar y restaurar puntos anteriores en la historia de nuestro repositorio. Sin él, estas referencias no existirían y necesitaríamos hashes de confirmación exactos para regresar a estados pasados específicos. Ahora, exploremos cómo Git nos permite navegar por estos estados pasados usando git checkout.

HEAD@{n}: Se refiere a una entrada específica del reflog, donde n es el índice. Por ejemplo, HEAD@{2} se refiere al tercer estado más reciente de HEAD.

git checkout HEAD@{2}

Usando git checkout para rastrear cambios pasados. Imagen por el autor.

branch@{time}: Se refiere al estado de una rama en un momento específico. Por ejemplo, main@{1.week.ago} se refiere al estado de la rama principal hace una semana, mientras que feature@{yesterday} se refiere al estado de la rama de características de ayer.

git checkout main@{1.week.ago}

Usando git checkout para rastrear cambios pasados. Imagen por el autor.

Cualificadores basados en el tiempo

git reflog no solo nos ayuda a restaurar estados pasados, sino que también nos permite compararlos. Dado que reflog rastrea actualizaciones de referencias, podemos usarlo para ver cómo ha cambiado nuestro repositorio con el tiempo. Ahora, veamos cómo git diff utiliza las entradas de reflog para comparar estados pasados y presentes.

A continuación se muestran ejemplos de cualificadores de tiempo que facilitan la restauración de su repositorio a un punto específico en el tiempo en lugar de depender únicamente de los números de índice de reflog.

git checkout HEAD@{1.minute.ago} # Estado de hace un minuto
git checkout HEAD@{1.hour.ago} # Estado de hace una hora
git checkout HEAD@{1.week.ago} # Estado de hace una semana
git checkout HEAD@{yesterday} # Estado desde ayer
git checkout HEAD@{2024-01-01.12:00:00} # Estado en una marca de tiempo específica

Comparando estados pasados con git diff

Puedes comparar estados pasados usando comandos como git diff. El siguiente comando compara el estado actual de la rama principal main@{0} con su estado de hace un día, main@{1.day.ago}. La salida mostrará cualquier diferencia entre estos dos instantáneas.

git diff main@{0} main@{1.day.ago}

Comparando estados pasados con git diff. Imagen por el Autor.

Casos de uso comunes para Git Reflog

Git reflog es una herramienta invaluable para recuperar cambios perdidos, deshacer errores y solucionar errores comunes de Git. A continuación se presentan algunos escenarios prácticos donde git reflog puede ayudar.

Deshacer un reseteo incorrecto

Si reseteaste accidentalmente tu rama usando git reset --hard, puedes usar reflog para restaurar tu estado anterior.

git reset --hard HEAD@{3}

Recuperando commits perdidos

Si eliminas accidentalmente una rama o pierdes commits debido a un reset o rebase, puedes encontrar el commit perdido usando git reflog.

git reflog

Localiza el hash del commit en la salida del reflog y reviértelo:

git checkout <commit-hash>

Una vez que verifiques el commit perdido, puedes crear una nueva rama para preservarlo:

git branch recovered-branch <commit-hash>

Corrigiendo un rebase fallido

Si un rebase sale mal, puedes usar git reflog para encontrar el commit antes del rebase y resetear tu rama. Identifica el commit antes del rebase y resétalo.

git reset --hard HEAD@{3} # Ajusta el número basado en la salida de reflog

Restaurando una rama eliminada

Si borras accidentalmente una rama, puedes recuperarla usando git reflog. Encuentra el último commit conocido de la rama eliminada y recriala:

git branch restored-branch <commit-hash>

Seguimiento del historial de stash

Git reflog también se puede usar para ver el historial de stash. El siguiente comando lista las operaciones de stash, permitiéndote recuperar stashes antiguos si es necesario. 

git reflog stash

Para aplicar una entrada de stash anterior, utiliza el siguiente comando:

git stash apply stash@{2}

Consulta nuestro Git Pull Forzado: Cómo Sobrescribir una Rama Local con Remota tutorial para aprender las mejores prácticas para sobrescribir cambios locales.

Subcomandos y Opciones de Git Reflog

Git proporciona varios subcomandos y opciones para gestionar e interactuar con los reflogs.

Subcomandos de reflog de Git

A continuación se presenta un desglose estructurado de los principales git reflog subcomandos y su uso.

git reflog show: Muestra las entradas de reflog para HEAD por defecto o para una referencia especificada como una rama.

git reflog show

Usando git reflog show para mostrar entradas para una referencia especificada. Imagen por Autor.

git reflog list: Este comando muestra todas las referencias con un reflog. Es útil para identificar ramas y referencias HEAD con entradas de reflog almacenadas.

git reflog list

git reflog delete <ref>@{<specifier>}: Elimina las entradas antiguas del reflog que exceden el límite de tiempo especificado. Por ejemplo, el siguiente comando elimina las entradas más antiguas de 30 días.

git reflog expire --expire=30.days.ago

git reflog delete <ref>@{<specifier>}: Elimina una entrada de reflog particular basada en su referencia y posición. El siguiente comando elimina la entrada de reflog en el índice 2 para HEAD.

git reflog delete HEAD@{2}

git reflog exists <ref>: Verifica si existe un reflog para una referencia específica. Por ejemplo, el comando a continuación devuelve éxito si la rama principal tiene un reflog.

git reflog exists main

Opciones para los subcomandos de git reflog

Las siguientes son las opciones disponibles para los subcomandos de git reflog y su uso.

--expire-unreachable=<time>: Elimina solo aquellas entradas de reflog que son inalcanzables desde cualquier referencia. Por ejemplo, el comando a continuación elimina las entradas de reflog inalcanzables que tienen más de 7 días.

git reflog expire --expire-unreachable=7.days.ago

--all: Procesa reflogs para todas las referencias, no solo para HEAD. El comando a continuación limpia todos los reflogs que tienen más de 60 días en todas las ramas.

git reflog expire --expire=60.days.ago --all

--dry-run: Simula la ejecución de un comando, mostrando lo que se eliminaría sin borrar realmente nada. Por ejemplo, el comando a continuación muestra qué entradas serían eliminadas.

git reflog expire --expire=30.days.ago --dry-run

--verbose: Proporciona una salida detallada sobre las acciones realizadas por el comando. El comando a continuación muestra detalles verbosos mientras expira entradas antiguas del reflog.

git reflog expire --expire=90.days.ago --verbose

Git Reflog vs. Git Log: Principales Diferencias

Tanto git log como git reflog ofrecen información sobre la historia de un repositorio, pero sirven para diferentes propósitos. Veamos estas diferencias para entender cómo cada uno puede ser utilizado para el control de versiones y estrategias de recuperación.

  • git log muestra el historial de commits siguiendo la ascendencia de los commits en una rama. Proporciona una vista cronológica de cómo ha evolucionado el contenido del repositorio.

  • git reflog registra actualizaciones a referencias como HEAD, ramas y alijos, incluyendo acciones como cambios de rama, reinicios, rebase y más. Realiza un seguimiento de cambios que pueden no ser parte de la ascendencia de confirmaciones.

  • git reflog es estrictamente local en tu máquina y no se comparte con repositorios remotos.

  • Mientras que git log no puede recuperar commits que ya no son parte de la genealogía de la rama, git reflog puede ayudar a recuperar commits “perdidos” rastreando actualizaciones de referencia, incluso si esos commits ya no son accesibles desde ninguna rama.

La tabla a continuación resume estas diferencias clave.

Feature git log git reflog
Rastrea commits No
Rastrea actualizaciones de referencia No
Compartido en remoto No
Puede recuperar commits perdidos No

Mejores prácticas para usar Git Reflog

Git reflog es una herramienta poderosa para recuperar commits perdidos y solucionar problemas de historial, pero usarla efectivamente requiere precaución. Aquí hay algunas mejores prácticas a seguir al trabajar con reflog.

  • Usar Reflog para Recuperación y Depuración: Si reseteó o rehizo incorrectamente una rama por accidente, verifique git reflog para encontrar una referencia anterior y restaurarla.

  • Tenga cuidado con git reset --hard: git reset --hard puede eliminar permanentemente los cambios no confirmados. Siempre verifique primero el reflog para asegurarse de que pueda recuperar si algo sale mal.

  • Haga copias de seguridad antes de ejecutar comandos destructivos: Para protegerse contra la pérdida de datos, implemente copias de seguridad automatizadas de sus repositorios de Git. Siempre almacene las copias de seguridad en un lugar seguro y fuera del sitio para garantizar la recuperabilidad en caso de falla de hardware u otros desastres.

  • No Te Fíes Únicamente de Reflog para Recuperaciones a Largo Plazo:Por defecto, las entradas de reflog se mantienen durante 90 días. Después de este período, pueden ser eliminadas y volverse irrecuperables. Envía regularmente tus commits a un repositorio remoto para asegurarte de que se preserven más allá de tu reflog local.

  • Usa git reflog expire para gestionar las entradas antiguas: Si el reflog de tu repositorio se vuelve desordenado, elimina las entradas antiguas o inaccesibles usando git reflog expire.

Conclusión

Gestionar eficazmente el historial de un proyecto en Git requiere más que solo comandos básicos. Explorar herramientas avanzadas que rastrean actualizaciones de referencia puede proporcionar una red de seguridad valiosa para recuperar commits perdidos, restaurar ramas eliminadas y corregir errores. Obtener experiencia práctica con estas herramientas, junto con comandos como git reset, git checkout y git revert, puede mejorar significativamente tu competencia en el control de versiones.

Tomar nuestros cursos no solo es una excelente manera de aprender, sino que también es una excelente forma de señalar a los empleadores que te tomas en serio el desarrollo de software. Con ese fin, recomiendo estudiar nuestra publicación de blog Top 20 Preguntas y Respuestas de Entrevista de Git para Todos los Niveles y realizar nuestra nueva pista de habilidades Git Fundamentals para convertirte en un experto en todo lo relacionado con Git.

Source:
https://www.datacamp.com/tutorial/git-reflog