■ espacio · carril de prosa

■ the answer first

Deshacer el último commit conservando los cambios: git reset --soft HEAD~1 (staged) o git reset HEAD~1 (unstaged).

¿Ya empujado? git revert HEAD — un commit nuevo que lo deshace, seguro en ramas compartidas.

reset --hard es la única línea que borra trabajo — y git reflog aún lo sabe, durante ~90 días.

LOS TRES CARRILES

Un commit de más, tres salidas. El flag decide dónde aterrizan tus cambios — sigue los carriles:

fig — el único carril que borra trabajo es --hard; el reflog es la cuneta que corre bajo los tres

CONSERVAR LOS CAMBIOS: LOS DOS COMANDOS

La situación más común: commitaste, viste una errata, faltaba un archivo, o te diste cuenta de que el cambio va en otro commit. Nada empujado aún. Deshaz el commit y devuelve todo a su sitio:

# commit fuera — los cambios vuelven al área de staging
git reset --soft HEAD~1

# los cambios vuelven al árbol de trabajo (unstaged) en su lugar
git reset HEAD~1

HEAD~1 significa "un commit antes de donde apunta HEAD ahora". Tras cualquiera de las dos órdenes tus archivos están intactos en disco — solo se movió el puntero de rama. Comprueba con git status: with --soft los cambios están staged, listos para volver a committear con las correcciones incluidas; sin flag quedan unstaged, así que puedes editar libremente primero.

verifica: git status → staged (--soft) o unstaged (por defecto) · git log --oneline -1 → el commit anterior

Un hábito más seguro cuando solo quieres añadir archivos al último commit es no deshacerlo en absoluto:

git add forgotten-file.txt
git commit --amend --no-edit

--amend sustituye el último commit in situ (aquí sin cambiar el mensaje). Ojo: enmendar un commit empujado reescribe la historia — más abajo.

LOS TRES FLAGS, LADO A LADO

Esta es la parte que merece memorizarse, porque el flag decide dónde acaban tus cambios — y si pueden perderse:

Flag¿Commit deshecho?Cambios en disco¿Staged?Uso típico
--softSíConservadosYesVolver a committear con arreglos menores
--mixed (por defecto)SíConservadosNoReagrupar cambios, re-stagear selectivamente
--hardSíBorrados—Tirar el trabajo entero
git revertNo (commit nuevo)Conservados—Deshacer un commit ya empujado

--hard es el único peligroso: descarta el commit y los cambios. Antes de cualquier hard reset, guarda en stash o rama lo que tengas:

git branch backup-before-reset   # seguro barato
git reset --hard HEAD~1          # commit + cambios fuera

¿Ya corriste la versión peligrosa? No todo está perdido — git reflog recuerda por dónde anduvo HEAD. El reflog conserva los commits huérfanos unos 90 días por defecto, así que "hice un hard-reset por error" casi siempre tiene remedio si actúas antes del garbage collection:

git reflog                       # o: git reset --hard <hash>
git reset --hard HEAD@{1}        # or: git reset --hard <hash>

verifica: git reflog → el commit descartado está en HEAD@{1}

¿YA EMPUJADO?

El historial compartido recibe un commit nuevo, nunca una reescritura. Si el commit está en una rama compartida — cualquier cosa que no sea tu propia rama de feature — no reescribas la historia. git revert calcula el cambio inverso y lo committea. Todo el que haga pull simplemente recibe un commit nuevo que elimina los cambios del viejo. Ni force-push, ni compañeros rotos:

git revert HEAD
git push

Undoing a run of commits is the same move over a range: Deshacer una tanda de commits es el mismo movimiento sobre un rango: . The alternative — — solo es aceptable en una rama sobre la que nadie más construye: — is only acceptable on a branch nobody else builds on: --force-with-lease rechaza el push si el remoto se movió desde tu último fetch; un --force a secas sobreescribe lo que haya aparecido. Forzar el push de ramas compartidas es como los equipos pierden commits y los logs de CI dejan misteriosamente de cuadrar con el checkout de nadie.

verifica: git log --oneline -2 → Revert "…" queda encima del commit deshecho

BUEN TRABAJO, DIRECCIÓN EQUIVOCADA

A veces el commit está bien — rama equivocada, o demasiado pronto. En vez de deshacerlo, muévelo. Apara el commit entero en una rama nueva, y luego limpia tu

git branch stash-commit          # apara el commit en una rama nueva
git reset --hard HEAD~1          # luego limpia tu rama actual

git cherry-pick <hash>           # estando en la rama destino

Entre reset --soft, cherry-pick and revert, no hay commit que no puedas reubicar o anular — el truco es elegir "mover" contra "deshacer" antes de estirar la mano hacia un flag.

LA PALABRA ES EL COMANDO

Media confusión es vocabulario: seis verbos que la gente teclea en el buscador, tres comandos que existen de verdad. Empareja la palabra de tu cabeza con el flag que lo hace:

La palabra que tecleasteLo que quieresEl comando¿Cambios conservados?
undo / uncommitcommit fuera, trabajo de vueltagit reset --soft HEAD~1sí — staged
undo, unstagedcommit fuera, trabajo de vuelta sueltogit reset HEAD~1sí — mixed
remove / dropcommit y ediciones fueragit reset --hard HEAD~1no — reflog ~90 días
revert / cancel, empujadodeshacer público, historia intactagit revert HEADsí — commit nuevo

Los verbos no son sinónimos en Git: revert jamás toca el pasado, reset lo reescribe. Di la palabra equivocada a un compañero y recibirás el comando equivocado. Toda la decisión, como checklist:

  1. Sin empujar, corregir y volver a committear → git reset --soft HEAD~1
  2. Sin empujar, re-stagear selectivamente → git reset HEAD~1 (mixed)
  3. Quiero que los cambios desaparezcan del todo → git reset --hard HEAD~1 (el reflog lo sabe, si te arrepientes)
  4. Ya empujado a una rama compartida → git revert HEAD
  5. El commit pertenece a otra rama → cherry-pick, no lo deshagas

¿Quieres que decidan por ti? El generador git-undo hace estas preguntas e imprime el comando. Un último consejo operativo: si un commit malo llegó de verdad a un servidor — un hook de despliegue torcido, un runner de CI desbocado tras un force-push — el siguiente sitio donde mirar son los logs de la máquina, no Git: en cualquier caja systemd, journalctl -u <service> -n 100 shows you exactly what ran and when. And when Git refuses to run at all — fatal: not a git repository — that is a different problem from undoing anything.

■ honest stamp Probado en: git 2.4x · Linux · macOS · Windows — cada comando corre tal cual. Publicado por primera vez 2026-09-03, ficha refrescada 2026-10-09. La tabla de flags, la ventana de ~90 días del reflog y el comportamiento de force-with-lease son valores por defecto documentados de git, tecleados por uso; nada en esta página es sintaxis hipotética.

fin de la página de deshacer · nada descargado · todo local