Hiciste un commit que quieres deshacer. ¿Y ahora qué?
Le pasa a todo el mundo. Haces commit demasiado pronto, incluyes un archivo que no debías, escribes el mensaje equivocado o te das cuenta de que el código simplemente no está bien. La buena noticia: Git está diseñado para manejar esto. La mejor noticia: en la mayoría de los casos, puedes deshacer un commit sin perder tu trabajo.
El enfoque correcto depende de una pregunta clave: ¿el commit ha sido pushado a un remote, o todavía es local? Los commits locales te dan más flexibilidad. Los commits pushados requieren una estrategia más segura porque otras personas pueden haber pullado tus cambios.
Deshacer un commit local con git reset
Si el commit todavía es local (no pushado), git reset es la herramienta más común. Mueve el puntero de branch hacia un commit anterior, deshaciendo efectivamente tu commit. Lo que sucede con esos cambios depende del flag que uses.
git reset --soft: deshacer el commit, mantener todo en staging
git reset --soft HEAD~1
Esto deshace el último commit pero mantiene todos los cambios en staging (en el índice). Tu directorio de trabajo no se toca. Es como si nunca hubieras ejecutado git commit -- estás de vuelta al momento justo antes de hacer el commit.
Cuándo usarlo: Quieres cambiar el mensaje del commit, añadir más archivos al commit o dividir el commit en otros más pequeños. Tu código está bien, solo hiciste commit prematuramente.
git reset --mixed: deshacer el commit, quitar los cambios del staging
git reset --mixed HEAD~1
Este es el comportamiento por defecto de git reset (puedes omitir el flag --mixed). Deshace el commit y quita los cambios del staging, pero tus archivos permanecen modificados en el directorio de trabajo. No se pierde nada.
Cuándo usarlo: Quieres repensar qué incluir en el commit. Quizás quieres poner en staging solo algunos archivos, o quieres revisar los cambios antes de volver a hacer commit.
git reset --hard: deshacer el commit, descartar todos los cambios
git reset --hard HEAD~1
Esto deshace el commit y elimina permanentemente todos los cambios. Tu directorio de trabajo se restablece para coincidir con el commit anterior. No hay forma de recuperar los cambios descartados mediante operaciones normales de Git.
Cuándo usarlo: Estás seguro de que no quieres los cambios en absoluto. Quizás hiciste commit de código experimental que no funcionó y quieres empezar de cero. Úsalo con precaución.
Retroceder más atrás
HEAD~1 se refiere a un commit antes del HEAD actual. Puedes ir más atrás:
git reset --soft HEAD~3
Esto deshace los últimos tres commits, combinando todos sus cambios en el área de staging. También puedes apuntar a un commit específico por su hash:
git reset --soft a1b2c3d
Corregir el último commit con git commit --amend
Si solo necesitas ajustar el último commit en lugar de deshacerlo por completo, --amend es la opción más rápida:
git commit --amend -m "corrected commit message"
Esto reemplaza el commit anterior con uno nuevo. También puedes usarlo para añadir archivos olvidados:
git add forgotten-file.ts
git commit --amend --no-edit
El flag --no-edit mantiene el mensaje de commit original. El resultado es un único commit corregido en lugar de una secuencia de commits "ups".
Importante: Como reset, amend reescribe el historial. Úsalo solo en commits que no han sido pushados. Si haces amend de un commit pushado y luego force-push, cualquiera que haya pullado el commit original tendrá problemas.
Deshacer un commit pushado con git revert
Una vez que un commit ha sido pushado a un remote compartido, no deberías reescribir el historial. Otros desarrolladores pueden haber basado su trabajo en ese commit. En su lugar, usa git revert:
git revert HEAD
Esto crea un nuevo commit que hace exactamente lo opuesto al commit objetivo. Si el commit original añadió una línea, el commit de revert la elimina. Si eliminó un archivo, el commit de revert lo restaura. El commit original permanece en el historial, y el revert se añade encima.
Cuándo usarlo: Cada vez que necesites deshacer un commit que ya ha sido pushado. Es seguro porque añade al historial en lugar de reescribirlo.
Revertir un commit más antiguo
Puedes revertir cualquier commit, no solo el más reciente:
git revert a1b2c3d
Git intentará crear un commit de revert que deshaga solo los cambios de ese commit específico. Si esos cambios se solapan con trabajo posterior, puede que obtengas un conflicto que necesite resolución manual.
Revertir múltiples commits
Para revertir un rango de commits:
git revert HEAD~3..HEAD
Esto crea commits de revert individuales para cada commit en el rango. Si prefieres un único commit de revert, añade el flag --no-commit y haz el commit manualmente:
git revert --no-commit HEAD~3..HEAD
git commit -m "revert last 3 commits"
Elegir el enfoque correcto
| Situación | Método | Qué pasa con tus cambios |
|---|---|---|
| Commit demasiado pronto, quiere re-stagar | git reset --soft HEAD~1 |
Los cambios permanecen en staging |
| Commit demasiado pronto, quiere retrabajar | git reset --mixed HEAD~1 |
Los cambios permanecen en el directorio de trabajo |
| Commit de algo que quiere descartar | git reset --hard HEAD~1 |
Los cambios se eliminan |
| Necesita corregir el mensaje o añadir un archivo | git commit --amend |
El commit anterior se reemplaza |
| Necesita deshacer un commit pushado de forma segura | git revert HEAD |
Un nuevo commit deshace los cambios |
Recuperarse de errores
Incluso si usas git reset --hard y te das cuenta de que no debías haberlo hecho, a menudo hay una forma de recuperarse. Git mantiene un registro de dónde ha apuntado HEAD, llamado reflog:
git reflog
Esto muestra una lista de posiciones recientes de HEAD. Puedes encontrar el commit que creías haber perdido y volver a él:
git reset --hard HEAD@{2}
El reflog es tu red de seguridad. Las entradas se mantienen durante 90 días por defecto, así que tienes una ventana generosa para recuperarte de errores.
Deshacer commits en GitSquid
GitSquid simplifica las operaciones de deshacer más comunes. Puedes presionar Cmd+Z (o Ctrl+Z en Windows y Linux) inmediatamente después de hacer commit para deshacer el último commit, manteniendo tus cambios en staging y listos para retrabajar. Para operaciones más específicas, hacer clic derecho en cualquier commit del grafo te da acceso a opciones de reset y revert a través de un menú contextual, para que puedas apuntar exactamente al commit que quieres deshacer sin memorizar flags.
Deshacer un commit de Git no tiene que ser estresante. Entiende la diferencia entre reset, amend y revert, sabe cuál se adapta a tu situación, y podrás corregir errores con confianza. La distinción más importante es simple: si es local, usa reset o amend. Si está pushado, usa revert.