Git reset: soft, mixed y hard, y cómo deshacer un reset --hard
git reset es de esos comandos que se aprenden a golpes. Lo usas una vez, borra más de lo que esperabas y de ahí en adelante lo miras con respeto.
Esta guía te lo explica con palabras simples y con comandos probados en un repositorio de prueba con Git 2.53.0. Los hashes aparecen recortados a 7 caracteres y los mensajes de Git, en inglés. Si apenas empiezas, pasa antes por la primera parte de la guía de Git.
En corto
- Qué hace:
git resetmueve tu rama (y con ella HEAD) a otro commit. --soft: deshace el commit y deja todo preparado en el staging.--mixed(el modo por defecto): deshace el commit y vacía el staging. Tus archivos quedan intactos.--hard: deshace el commit, vacía el staging y sobrescribe tus archivos.- “git reset -1” no existe. Lo que quieres escribir es
git reset HEAD~1. - Si te arrepientes de un
--hard:git reflogmuestra el commit ygit reset --hard <hash>lo trae de vuelta. Los cambios que nunca guardaste con commit no se recuperan. - Si ya hiciste push: no uses reset. Usa git revert.
¿Qué hace git reset?
Git maneja tu trabajo en tres lugares. Verlos así hace que todo lo demás tenga sentido:
- El historial: los commits. La rama y HEAD apuntan al último.
- El staging: lo que dejaste preparado con
git addpara el próximo commit. - Tus archivos: lo que ves en la carpeta del proyecto (el working tree, el árbol de trabajo).
git reset <commit> hace siempre lo mismo en el primer lugar: mueve la rama a ese commit. Lo que cambia entre un modo y otro es hasta dónde llega después. Según la documentación oficial, si no indicas modo, Git usa --mixed.
git reset —soft, —mixed y —hard: la diferencia
Tabla 1: Qué toca cada modo de git reset
| Modo | Mueve la rama | Staging | Tus archivos |
|---|---|---|---|
--soft | Sí | Se conserva | Se conservan |
--mixed (por defecto) | Sí | Se vacía | Se conservan |
--hard | Sí | Se vacía | Se sobrescriben: cambios perdidos |
Cómo leerla: cada columna dice qué le pasa a esa parte de tu trabajo. Solo --hard toca tus archivos.
Los bloques bash son lo que escribes en la terminal, dentro de la carpeta de un repositorio. Están en sintaxis bash: en Windows úsalos en Git Bash o WSL. Los bloques text son la salida que debería aparecer.
Partimos de un repositorio con tres commits:
git log --oneline
0f807bc Commit tres
e9a9ad9 Commit dos
8a73f8f Commit uno
Cada ejemplo parte de cero desde estos tres commits. Si los repites uno tras otro en el mismo repositorio, tus hashes, tu git status y tu reflog se verán distintos; para que coincidan, crea el repositorio de nuevo antes de cada ejemplo.
git reset —soft HEAD~1
Deshace el commit, pero deja sus cambios preparados, como si estuvieras a punto de hacer git commit otra vez:
git reset --soft HEAD~1
git log --oneline
git status --short
e9a9ad9 Commit dos
8a73f8f Commit uno
A tres.txt
La A en la primera columna significa que tres.txt sigue en el staging. Sirve para rehacer el último commit (por ejemplo, para corregir el mensaje) o para unir varios en uno con git reset --soft HEAD~3 y un solo git commit.
git reset HEAD~1 (—mixed)
Sin ningún modo, el commit se deshace y el staging se vacía, pero tus archivos siguen en la carpeta:
git reset HEAD~1
git status --short
?? tres.txt
Ahora tres.txt aparece como archivo sin seguimiento (??). Sigue en tu carpeta, solo que Git ya no lo tiene preparado. Sirve para volver a elegir qué entra en el commit. Y responde una duda frecuente: git reset HEAD~1 y git reset --mixed HEAD~1 son exactamente lo mismo.
git reset —hard HEAD~1
git reset --hard HEAD~1
ls
HEAD is now at e9a9ad9 Commit dos
dos.txt
uno.txt
El commit se fue, el staging quedó vacío y tres.txt ya no está en la carpeta. La documentación lo dice así: --hard sobrescribe los archivos con la versión del commit y elimina los archivos rastreados que no están en él. Úsalo cuando de verdad quieras descartar todo. El resto del tiempo, --soft o --mixed son más amables.
git reset HEAD~1, HEAD^ y un hash: a dónde apuntas
HEAD es el commit en el que estás parado. El segundo argumento de git reset le dice a qué commit moverte. Hay tres formas de nombrarlo:
for r in HEAD^ HEAD~1 HEAD~2; do echo -n "$r -> "; git rev-parse --short $r; done
HEAD^ -> e9a9ad9
HEAD~1 -> e9a9ad9
HEAD~2 -> 8a73f8f
Este for es de bash. En Windows ejecútalo en Git Bash o WSL, o escribe git rev-parse --short HEAD~1 y cambia el valor a mano.
HEAD~1es el commit anterior al actual.HEAD~2retrocede dos,HEAD~3tres, y así.HEAD^apunta al mismo sitio queHEAD~1: el padre directo del commit actual. La diferencia aparece solo en commits de merge, que tienen dos padres. AhíHEAD^es el primero yHEAD^2es el segundo (lo explica gitrevisions).- Un hash que saques de
git log --oneline. Sirve cuando quieres volver a un punto concreto y no quieres contar commits:
git reset --hard 8a73f8f
HEAD is now at 8a73f8f Commit uno
¿Por qué “git reset -1” y “git reset HEAD -1” dan error?
Porque -1 no es una forma válida de decir “un commit atrás”. Para Git, un guion seguido de algo es una opción, y -1 no es ninguna. Esto fue lo que respondió:
git reset -1
error: unknown switch `1'
usage: git reset [--mixed | --soft | --hard | --merge | --keep] [-q] [<commit>]
Con git reset HEAD -1 y con git reset --soft -1 pasa lo mismo. Lo que casi siempre se quiere decir es esto:
git reset -1ogit reset HEAD -1→git reset HEAD~1git reset soft -1→git reset --soft HEAD~1git reset hard HEAD→git reset --hard HEAD
Fíjate en dos detalles. El modo lleva dos guiones (--soft, no soft). Sin ellos, Git cree que soft o hard es el nombre de un commit y falla:
fatal: ambiguous argument 'hard': unknown revision or path not in the working tree.
Y “un commit atrás” se escribe con la tilde: HEAD~1.
Otra búsqueda parecida es “git rollback”. No existe. Si lo escribes, Git responde git: 'rollback' is not a git command. Lo que la gente suele querer con esa palabra es git reset (si el commit es solo tuyo) o git revert (si ya lo compartiste).
git reset de un solo archivo frente a git restore
git reset también acepta nombres de archivo. En ese caso no mueve la rama: solo saca el archivo del staging. Partimos de uno.txt modificado y agregado con git add:
git status --short
git reset uno.txt
git status --short
M uno.txt
Unstaged changes after reset:
M uno.txt
M uno.txt
El cambio sigue en el archivo (mira la M en la segunda columna), pero ya no está preparado. git restore --staged uno.txt hace lo mismo. Para descartar el cambio del archivo:
git restore uno.txt
git status --short
cat uno.txt
uno
El árbol quedó limpio (git status --short no imprimió nada) y uno.txt volvió a su contenido del último commit. Este paso no se puede deshacer, porque ese cambio nunca estuvo en un commit.
Dos reglas más. git restore existe desde Git 2.23. Y git reset --hard no acepta archivos:
fatal: Cannot do hard reset with paths.
Tabla 2: Reset frente a restore
| Quiero… | Comando | Qué pasa con mi cambio |
|---|---|---|
| Retroceder commits | git reset --soft, --mixed o --hard | Depende del modo |
| Sacar un archivo del staging | git restore --staged archivo (o git reset archivo) | Se conserva en el archivo |
| Descartar los cambios de un archivo | git restore archivo | Se pierde |
| Dejar un archivo como en el último commit | git restore --source=HEAD --staged --worktree archivo | Se pierde |
La regla corta: reset es para mover commits; restore es para archivos.
¿Se puede deshacer un git reset —hard?
Depende de qué perdiste.
Si lo que perdiste eran commits, sí. Git guarda en el reflog un registro de los lugares donde ha estado HEAD, incluso los que ya no aparecen en git log. Después del reset --hard HEAD~1 de arriba:
git reflog
e9a9ad9 HEAD@{0}: reset: moving to HEAD~1
0f807bc HEAD@{1}: commit: Commit tres
e9a9ad9 HEAD@{2}: commit: Commit dos
8a73f8f HEAD@{3}: commit (initial): Commit uno
El commit 0f807bc sigue ahí. Para traerlo de vuelta usa su hash o su posición en el reflog:
git reset --hard HEAD@{1}
ls
HEAD is now at 0f807bc Commit tres
dos.txt
tres.txt
uno.txt
tres.txt regresó. Según la documentación de reflog, por defecto las entradas se conservan 90 días (gc.reflogExpire), y las que ya no son alcanzables desde la rama, 30 días (gc.reflogExpireUnreachable). En PowerShell, HEAD@{1} necesita comillas: "HEAD@{1}".
Ahora la parte incómoda. El reflog recuerda commits, no cambios sueltos. Con un archivo modificado sin commit y uno nuevo en el staging:
git status --short
git reset --hard HEAD
git status --short
cat uno.txt
A nuevo.txt
M uno.txt
HEAD is now at 0f807bc Commit tres
uno
La línea agregada a uno.txt desapareció y nuevo.txt también. Ni el reflog los registra.
Tabla 3: Qué puedes recuperar después de un reset —hard
| Lo que perdiste | ¿Se recupera? | Cómo |
|---|---|---|
| Commits que “desaparecieron” | Sí | git reflog y git reset --hard <hash> |
Cambios modificados que nunca guardaste con commit ni con git add | No | Git no tiene registro de ellos |
Archivos nuevos que alcanzaste a pasar por git add | A veces | Git guarda su contenido como objeto huérfano; git fsck --lost-found lo lista |
El último caso es un rescate de último recurso: sin nombre de archivo y sujeto a que Git limpie esos objetos. La conclusión práctica es una sola: haz commit antes de arriesgar. Un commit “feo” que luego deshaces con --soft es mejor que un trabajo que no existe en ningún lado.
Un atajo útil: justo después de un reset, Git deja guardado el punto de partida en ORIG_HEAD. Si acabas de equivocarte, git reset --hard ORIG_HEAD te devuelve ahí.
¿Cuándo NO usar git reset?
Cuando el commit que quieres deshacer ya lo subiste a una rama que otras personas usan.
reset reescribe el historial. Si lo haces en un commit que ya hiciste push, tu rama queda con menos commits que el remoto y Git rechaza el siguiente push normal. Forzarlo con --force arregla tu lado, pero deja a tus compañeros con una copia del commit que tú borraste.
Para ese caso existe git revert: no borra nada, crea un commit nuevo que anula el anterior. La comparación completa, con el escenario del remoto probado paso a paso, está en Git reset vs git revert.
Tabla 4: Qué comando uso según mi situación
| Situación | Comando |
|---|---|
| El commit solo está en mi máquina, quiero rehacerlo | git reset --soft HEAD~1 |
| El commit solo está en mi máquina, quiero reelegir qué entra | git reset HEAD~1 |
| El commit solo está en mi máquina y no lo quiero para nada | git reset --hard HEAD~1 |
| El commit ya está en una rama compartida | git revert <hash> |
| Solo quiero sacar un archivo del staging | git restore --staged <archivo> |
Me arrepentí de un reset --hard | git reflog y git reset --hard <hash> |
Para probarlo sin riesgo, crea una carpeta de juguete, haz tres commits y repite los ejemplos de esta guía. Romper algo ahí no le cuesta nada a nadie.
Fuentes
Consultadas el 27 de octubre de 2026.
- git reset: modos
--soft,--mixed(por defecto) y--hard, y reset con rutas. - git reflog: registro de movimientos y expiración por defecto (90 y 30 días).
- git restore:
--staged,--worktreey--source. - gitrevisions:
HEAD~n,HEAD^y^2. - En este blog: Git reset vs git revert y Ramas, reset y revert para experimentar con IA.
Más allá del código: estrategia, escalabilidad e impacto
Lecturas clave para conectar la arquitectura técnica con el valor de negocio y rentabilidad.

Análisis de la Decisions API de OpenAI (beta): respuestas tipadas con probabilidades, entrada de imágenes y precio por token, frente a Jev y Laya.

Segunda parte de la guía de Git para vibe coders: qué son las ramas, cómo verlas, crearlas, fusionarlas y eliminarlas (git branch, git switch, git merge), cómo resolver un conflicto de merge y qué comando usar para deshacer errores.

Aprende a diseñar la arquitectura de tu sitio web: silos temáticos, profundidad de clics vs URLs, navegación facetada sin problemas de indexación y migas de pan con Schema.
