Este es el capítulo que hace que se te quite el miedo, y por eso lo pongo antes que nada de la parte que sigue. Casi todo lo que crees que perdiste está ahí 🧯
La frase que me han dicho más veces es "borré tres días de trabajo". Y casi siempre la respuesta cabe en una línea.
El log y el reflog no son lo mismo
git log | git reflog | |
|---|---|---|
| Qué muestra | La historia oficial | Cada vez que te moviste |
| Incluye lo que "borraste" | No | Sí |
| Se comparte | Sí | No, es de tu máquina |
| Cuánto dura | Para siempre | 90 días por defecto |
Eso de que el reflog no se comparte importa: es tuyo y de tu carpeta. Si clonas de nuevo el proyecto, el reflog no viene 🧳
Perder algo a propósito
Armamos un proyecto con historia y lo rompemos:
mkdir ventas-miss-yera cd ventas-miss-yera git init -q printf 'ciudad,monto\nLima,1200\n' > ventas.csv git add ventas.csv git commit -q -m "Primeras ventas de Lima" printf 'Arequipa,890\n' >> ventas.csv git add ventas.csv git commit -q -m "Entran las ventas de Arequipa" printf 'canal,monto\nBodegas,4200\n' > canales.csv git add canales.csv git commit -q -m "Entra el reporte por canal" git log --oneline
ac55194 Entra el reporte por canal 508ad4d Entran las ventas de Arequipa 54da6e2 Primeras ventas de Lima
Tres commits. Y ahora el desastre clásico:
git reset --hard HEAD~2
git log --oneline
ls
HEAD is now at 54da6e2 Primeras ventas de Lima 54da6e2 Primeras ventas de Lima ventas.csv
Un commit, un archivo, y el reporte por canal desapareció. Este es el momento del "se me fue el trabajo de dos días" 😰
El reflog
git reflog
54da6e2 HEAD@{0}: reset: moving to HEAD~2
ac55194 HEAD@{1}: commit: Entra el reporte por canal
508ad4d HEAD@{2}: commit: Entran las ventas de Arequipa
54da6e2 HEAD@{3}: commit (initial): Primeras ventas de Lima
Ahí está todo. Cada línea es un movimiento, con su hash y qué lo causó. El
HEAD@{1} es "donde estabas justo antes", HEAD@{2} el
anterior, y así 🧭
Volver
git reset --hard HEAD@{1}
git log --oneline
ls
cat canales.csv
HEAD is now at ac55194 Entra el reporte por canal ac55194 Entra el reporte por canal 508ad4d Entran las ventas de Arequipa 54da6e2 Primeras ventas de Lima canales.csv ventas.csv canal,monto Bodegas,4200
Los tres commits de vuelta y el archivo también. Eso es todo el capítulo 🎉
Volver a un hash concreto
Cuando hay muchos movimientos, es más seguro copiar el hash de la línea que quieres que contar posiciones:
git reset --hard HEAD~1 git log --oneline git reflog --format="%h %gs" | head -4
HEAD is now at 508ad4d Entran las ventas de Arequipa
508ad4d Entran las ventas de Arequipa
54da6e2 Primeras ventas de Lima
508ad4d reset: moving to HEAD~1
ac55194 reset: moving to HEAD@{1}
54da6e2 reset: moving to HEAD~2
ac55194 commit: Entra el reporte por canal
Ese hash de la izquierda se copia y se usa directamente. No hay que acordarse de nada.
Una rama borrada también vuelve
git switch -q -c reporte-por-ciudad printf 'Cusco,760\n' >> ventas.csv git add ventas.csv git commit -q -m "Entran las ventas de Cusco" git switch -q - git branch -D reporte-por-ciudad git branch git reflog --format="%h %gs" | head -3
Deleted branch reporte-por-ciudad (was 721b81f). * main 508ad4d checkout: moving from reporte-por-ciudad to main 721b81f commit: Entran las ventas de Cusco 508ad4d checkout: moving from main to reporte-por-ciudad
La rama ya no está en la lista, pero su commit sigue en el reflog. Se recupera creando una rama nueva en ese punto:
git switch -q -c reporte-recuperado HEAD@{1}
git log --oneline -2
cat ventas.csv
721b81f Entran las ventas de Cusco 508ad4d Entran las ventas de Arequipa ciudad,monto Lima,1200 Arequipa,890 Cusco,760
Cusco volvió. Borrar una rama nunca borra sus commits, solo quita el nombre 🏷️
Lo único que no vuelve
Lo que nunca fue commit. Si editaste un archivo y no hiciste
git add ni commit, Git no tiene copia y no hay nada
que recuperar.
De ahí la costumbre que me ahorra sustos: antes de cualquier cosa que suene peligrosa, un commit, aunque el mensaje diga "a medias". Se puede limpiar después 🧷
La trampa
Te equivocaste de rama y guardaste tres commits donde no era. Buscas cómo deshacer, encuentras un reset --hard en un foro y lo pegas.
$ git reset --hard HEAD~3 HEAD is now at 3c1f80a Primeras ventas de Lima $ git log --oneline 3c1f80a Primeras ventas de Lima # y los tres commits del reporte por canal?
Qué está mal
Están ahí, pero no en el log 😅
Lo que hizo el reset fue mover la etiqueta de dónde estás, no borrar los commits. Siguen dentro de la carpeta .git, esperando, y se ven con git reflog.
El susto de "perdí tres días" casi siempre es esto: el trabajo está y lo que se perdió es el camino para llegar. El reflog es ese camino.
Lo que sí se pierde de verdad es lo que nunca llegó a ser commit. Por eso la costumbre más barata de todas: commit antes de cualquier cosa que suene peligrosa.
Comprueba que se entendió
Comprueba que lo tienes
Hiciste git reset --hard y tu log perdió tres commits. ¿Qué haces?
git reflogy vuelvo al punto anterior- Clono el proyecto otra vez desde GitHub
- Los vuelvo a escribir, no queda otra
- Busco los archivos en la papelera del sistema
Ejercicios
1. Construye algo que perder
Tres commits en el catálogo de bodegas.
cd .. mkdir catalogo cd catalogo git init -q printf 'bodega,ciudad\nBodega Inti,Cusco\n' > bodegas.csv git add bodegas.csv git commit -q -m "Catalogo inicial de bodegas" printf 'Minimarket Sol,Trujillo\n' >> bodegas.csv git add bodegas.csv git commit -q -m "Entra el minimarket de Trujillo" printf 'canal,monto\nBodegas,4200\n' > canales.csv git add canales.csv git commit -q -m "Entra el reporte por canal" git log --oneline
9f37666 Entra el reporte por canal 4cb519a Entra el minimarket de Trujillo a9874ae Catalogo inicial de bodegas
Tres commits y dos archivos.
2. Rómpelo
Un reset duro de dos commits.
git reset --hard HEAD~2
git log --oneline
ls
HEAD is now at a9874ae Catalogo inicial de bodegas a9874ae Catalogo inicial de bodegas bodegas.csv
Uno solo y el CSV de canales desapareció. Tranqui 🧘♀️
3. Mira el reflog
Todos tus movimientos, incluidos los que el log ya no muestra.
git reflog
a9874ae HEAD@{0}: reset: moving to HEAD~2
9f37666 HEAD@{1}: commit: Entra el reporte por canal
4cb519a HEAD@{2}: commit: Entra el minimarket de Trujillo
a9874ae HEAD@{3}: commit (initial): Catalogo inicial de bodegas
El HEAD@{1} es donde estabas justo antes del reset.
4. Vuelve
Recupera los tres commits.
git reset --hard HEAD@{1}
git log --oneline
ls
HEAD is now at 9f37666 Entra el reporte por canal 9f37666 Entra el reporte por canal 4cb519a Entra el minimarket de Trujillo a9874ae Catalogo inicial de bodegas bodegas.csv canales.csv
Todo de vuelta, incluidos los archivos.
5. Borra una rama y recupérala
Las ramas borradas también vuelven.
git switch -q -c precios-por-canal printf 'Horeca,3100\n' >> canales.csv git add canales.csv git commit -q -m "Entra el canal horeca" git switch -q - git branch -D precios-por-canal git switch -q -c precios-recuperado HEAD@{1} cat canales.csv git branch
Deleted branch precios-por-canal (was 6a3cf7b). canal,monto Bodegas,4200 Horeca,3100 main * precios-recuperado
El canal horeca estaba esperando en el reflog 🌿
6. Mira el reflog de una rama concreta
El reflog también existe por rama, no solo para
HEAD.
git switch -q main
git reflog show main --format="%h %gs"
9f37666 reset: moving to HEAD@{1}
a9874ae reset: moving to HEAD~2
9f37666 commit: Entra el reporte por canal
4cb519a commit: Entra el minimarket de Trujillo
a9874ae commit (initial): Catalogo inicial de bodegas
Útil cuando la que se movió de más fue una rama y no tú.
7. Pide un punto del reflog que no existe
Prueba a pedir un movimiento muy anterior en un repositorio recién creado.
git show HEAD@{50}
fatal: log for 'HEAD' only has 10 entries
Git te dice cuántos movimientos hay de verdad en vez de inventarse uno 🛑
Lo que te llevas
Casi nada se pierde: el reflog guarda 90 días de movimientos. Lo único irrecuperable es lo que nunca fue commit.