Para deshacer el último commit en Git tienes tres opciones según lo que quieras conservar: git reset --soft HEAD~1 elimina el commit pero mantiene los cambios preparados; git reset --hard HEAD~1 elimina el commit y los cambios; y git revert HEAD crea un nuevo commit que anula el anterior sin reescribir el historial, lo que lo convierte en la opción segura si ya has hecho push.
A continuación verás cuándo usar cada una, cómo corregir un commit en lugar de borrarlo (--amend) y cómo recuperar un commit que creías perdido con git reflog.
Primero: ¿has hecho push?
Esta pregunta decide todo lo demás.
- No has hecho push (el commit solo existe en tu máquina): puedes reescribir el historial con
git reseto--amendsin molestar a nadie. - Sí has hecho push a una rama compartida: no reescribas el historial. Usa
git revert, que añade un commit nuevo en lugar de borrar el existente. Si fuerzas un push tras un reset, el resto del equipo tendrá un historial distinto al tuyo y los conflictos están garantizados.
Opción 1: git reset (deshacer en local)
git reset mueve la referencia de la rama (HEAD) a un commit anterior. HEAD~1 significa “un commit antes del actual”. Lo que ocurre con los cambios de ese commit depende del modo:
# Elimina el commit; los cambios quedan en el área de preparación (staged)
git reset --soft HEAD~1
# Elimina el commit; los cambios quedan en el directorio de trabajo, sin preparar (es el modo por defecto)
git reset --mixed HEAD~1
git reset HEAD~1
# Elimina el commit Y descarta los cambios. Irreversible salvo con reflog.
git reset --hard HEAD~1
| Modo | ¿Borra el commit? | ¿Mantiene los cambios? | ¿Dónde quedan? |
|---|---|---|---|
--soft |
Sí | Sí | Preparados (staged), listos para un nuevo commit |
--mixed (por defecto) |
Sí | Sí | En el directorio de trabajo, sin preparar |
--hard |
Sí | No | Se descartan |
Un caso típico: has hecho commit demasiado pronto y quieres añadir algo más. git reset --soft HEAD~1, añades los archivos que faltan y vuelves a hacer commit.
Para deshacer varios commits, cambia el número: HEAD~3 retrocede tres.
Opción 2: git commit –amend (corregir, no borrar)
Si lo que quieres es cambiar el mensaje del último commit o añadirle un archivo olvidado, no necesitas deshacerlo:
# Cambiar solo el mensaje
git commit --amend -m "Mensaje corregido"
# Añadir un archivo olvidado al último commit, manteniendo el mensaje
git add archivo-olvidado.js
git commit --amend --no-edit
--amend sustituye el último commit por uno nuevo (con un hash distinto). Es, por tanto, una reescritura del historial: aplica la misma regla de no usarlo si ya has hecho push a una rama compartida.
Opción 3: git revert (deshacer sin reescribir)
git revert crea un commit nuevo que aplica los cambios inversos al commit indicado. El historial conserva tanto el commit original como su anulación, por lo que es seguro en ramas compartidas.
# Anula el último commit y abre el editor para el mensaje
git revert HEAD
# Igual, sin abrir el editor
git revert --no-edit HEAD
# Anular un commit concreto por su hash
git revert a1b2c3d
Si el commit a revertir es un merge, necesitarás indicar qué padre conservar con -m 1; la documentación de git-revert lo explica con detalle.
Si ya has hecho push y aun así necesitas reescribir
Hay situaciones en las que un reset tras push es inevitable (por ejemplo, has subido una contraseña por error y necesitas eliminarla del historial). En ese caso:
git reset --hard HEAD~1
git push --force-with-lease
--force-with-lease es preferible a --force: solo sobrescribe la rama remota si nadie ha subido nada desde tu último fetch, lo que evita borrar trabajo ajeno sin querer. Avisa al equipo, porque tendrán que actualizar su copia. Y recuerda que un secreto publicado debe considerarse comprometido y rotarse aunque lo borres del historial.
He hecho un reset –hard y necesito recuperar el commit
git reflog guarda un registro de todos los sitios por los que ha pasado HEAD en las últimas semanas, incluidos los commits que ya no están en ninguna rama:
git reflog
# a1b2c3d HEAD@{0}: reset: moving to HEAD~1
# e4f5g6h HEAD@{1}: commit: Añade validación del formulario
# ...
# Volver al estado anterior al reset
git reset --hard e4f5g6h
Mientras Git no haya ejecutado su recolección de basura (por defecto, los objetos sin referencia se conservan al menos 30 días en el reflog), el commit sigue ahí.
Qué comando usar: resumen
| Quiero… | Comando |
|---|---|
| Rehacer el commit con más cambios (sin push) | git reset --soft HEAD~1 |
| Volver a editar los archivos antes de commitear (sin push) | git reset HEAD~1 |
| Tirar el commit y sus cambios (sin push) | git reset --hard HEAD~1 |
| Cambiar el mensaje o añadir un archivo (sin push) | git commit --amend |
| Deshacer un commit ya publicado | git revert HEAD |
| Recuperar un commit tras un reset equivocado | git reflog + git reset --hard <hash> |
Conclusión
Antes de deshacer un commit, pregúntate si ya lo has compartido. Si no, git reset (con el modo adecuado) o --amend te dan control total. Si sí, git revert mantiene el historial coherente para todo el equipo. Y, pase lo que pase, git reflog es la red de seguridad: en Git es muy difícil perder un commit de verdad.