Deshacer el último commit en Git sin perder nada
Deshacer el último commit en Git de forma segura: reset --soft conserva los cambios, --mixed los desescala y revert corrige commits ya publicados.
Remove, delete, cancel o undo el último commit — sea cual sea el verbo que buscaste, el comando que conserva los cambios es el mismo. TL;DR: para deshacer el último commit conservando los cambios, ejecuta git reset --soft HEAD~1 (los cambios quedan en el staging) o git reset HEAD~1 (quedan en tu árbol de trabajo). Si el commit ya se publicó, ejecuta git revert HEAD — crea un commit nuevo que lo deshace sin reescribir el historial. Esos tres comandos cubren casi todos los momentos de «hice commit demasiado pronto». El resto de esta guía recorre cada caso con comandos listos para pegar, explica la diferencia entre --soft, --mixed y --hard, y muestra cómo recuperar todo si algo sale mal. Cada comando de aquí abajo funciona en cualquier instalación reciente de Git en Linux, macOS o Windows.
¿Cómo deshago el último commit sin perder los cambios?
La situación más común: hiciste commit, luego viste un typo, un archivo que faltaba, o te diste cuenta de que el cambio pertenece a otro commit. Nada se ha publicado todavía. Deshaz el commit y devuelve todo a su lugar:
# El commit desaparece del historial — los cambios vuelven al área de staging
git reset --soft HEAD~1
# Los cambios vuelven al árbol de trabajo (sin staging) en su lugar
git reset HEAD~1
HEAD~1 significa «un commit antes del punto donde apunta HEAD ahora». Después de cualquiera de los dos comandos tus archivos están intactos en disco — solo se movió el puntero de la rama. Compruébalo con git status: con --soft los cambios quedan en staging, listos para un nuevo commit con los arreglos incluidos; sin flag quedan fuera del staging, así que puedes editar libremente primero.
Un hábito más seguro cuando solo quieres agregar archivos al último commit es no deshacerlo en absoluto:
git add forgotten-file.txt
git commit --amend --no-edit
--amend reemplaza el último commit en el sitio (aquí sin cambiar el mensaje). Ojo: enmendar un commit ya publicado reescribe el historial — más sobre eso abajo.
¿Qué diferencia hay entre --soft, --mixed y --hard?
Esta es la parte que vale memorizar, porque el flag decide dónde terminan tus cambios — y si pueden perderse:
| Flag | ¿Deshace el commit? | Cambios en disco | ¿Quedan en staging? | Uso típico |
|---|---|---|---|---|
--soft |
Sí | Se conservan | Sí | Rehacer el commit con arreglos pequeños |
--mixed (por defecto) |
Sí | Se conservan | No | Reagrupar cambios y re-escalar a elección |
--hard |
Sí | Borrados | — | Tirar el trabajo a la basura por completo |
git revert |
No (commit nuevo) | Se conservan | — | Deshacer un commit ya publicado |
--hard es el único peligroso: descarta el commit y los cambios. Antes de cualquier reset --hard, guarda lo tuyo en un stash o una rama:
git branch backup-before-reset # seguro barato
git reset --hard HEAD~1 # commit + cambios fuera
Si ya corriste la versión peligrosa, no todo está perdido — git reflog recuerda por dónde anduvo HEAD:
git reflog # encuentra el hash del commit que perdiste
git reset --hard HEAD@{1} # o: git reset --hard <hash>
El reflog conserva los commits huérfanos durante unos 90 días por defecto, así que un «hice hard-reset por error» es casi siempre recuperable si actúas antes del garbage collection.
¿Y si ya hice push del commit?
Si el commit está en una rama compartida (cualquier cosa que no sea tu propia rama de feature), no reescribas el historial. Usa git revert, que calcula el cambio opuesto y lo confirma como commit:
git revert HEAD
git push
Todos los que hagan pull simplemente reciben un commit nuevo que elimina los cambios del anterior. Sin force-push, sin colegas rotos. Si necesitas deshacer una racha de commits, revierte un rango: git revert --no-commit HEAD~3..HEAD && git commit.
La alternativa — git reset --hard HEAD~1 && git push --force-with-lease — solo es aceptable en una rama sobre la que nadie más construye, y --force-with-lease (nunca --force a secas) es la única forma segura, porque se niega a sobrescribir si alguien publicó mientras tanto. Forzar el push en ramas compartidas es como los equipos pierden commits y los logs de CI dejan misteriosamente de coincidir con el checkout de cualquiera.
¿Cómo deshago el último commit pero lo guardo para después?
A veces el commit es buen trabajo en la dirección equivocada — en la rama incorrecta, o demasiado pronto. En vez de deshacerlo, muévelo:
git branch stash-commit # estaciona el commit en una rama nueva
git reset --hard HEAD~1 # y luego limpia tu rama actual
O llévate solo ese commit a otra rama sin tocar la actual:
git cherry-pick <hash> # estando en la rama de destino
Entre reset --soft, cherry-pick y revert, no hay commit que no puedas reubicar o anular — el truco está en elegir entre «mover» y «deshacer» antes de alcanzar un flag.
Undo, revert, reset, remove, cancel — cada palabra es un comando
Media confusión es de vocabulario: seis verbos que la gente escribe en el buscador, tres comandos que existen de verdad. Empareja la palabra que tienes en la cabeza con el flag que lo hace:
| La palabra escrita | Lo que quieres | El comando | ¿Cambios conservados? |
|---|---|---|---|
| undo / uncommit | commit fuera, trabajo de vuelta | git reset --soft HEAD~1 | sí — staged |
| undo, sin staging | commit fuera, trabajo suelto | git reset HEAD~1 | sí — mixed |
| remove / drop | commit y cambios eliminados | git reset --hard HEAD~1 | no — reflog ~90 días |
| revert / cancel, pushed | deshacer público, historial intacto | git revert HEAD | sí — commit nuevo |
Estos verbos no son sinónimos en Git: revert nunca toca el pasado, reset lo reescribe. La palabra equivocada dicha a un compañero devuelve el comando equivocado.
¿Qué método de deshacer uso? Guía rápida de decisión
- No publicado, quieres corregir y volver a hacer commit →
git reset --soft HEAD~1 - No publicado, quieres re-escalar selectivamente →
git reset HEAD~1(mixed) - Quieres los cambios fuera por completo →
git reset --hard HEAD~1(el reflog sabe, por si te arrepientes) - Ya publicado en una rama compartida →
git revert HEAD - El commit pertenece a otra rama →
cherry-pick, no lo deshagas
¿Prefieres que la decisión venga hecha? El generador de git undo hace estas tres preguntas y te imprime el comando.
Un último consejo operativo: si un commit malo sí llegó a un servidor — un hook de deploy arruinado, un runner de CI portándose mal tras un force-push — el siguiente lugar donde mirar son los logs de la máquina, no Git. En cualquier caja con systemd, journalctl -u <service> -n 100 te muestra exactamente qué corrió y cuándo; nuestra chuleta de journalctl trae los patrones listos para pegar. Y si tu flujo incluye LLM locales para revisar diffs, comparamos las dos opciones principales en Ollama vs LM Studio.