Deshacer cambios sin romper el historial: la idea clave
En Git, “deshacer” puede significar cosas distintas según el estado del cambio: puede que aún esté en tu directorio de trabajo, que esté en el área de preparación (staging), que ya sea un commit local, o que ya esté publicado en una rama compartida. La regla práctica es: si ya publicaste, evita reescribir el historial; si aún no publicaste, puedes reordenar o borrar commits locales con más libertad.
Antes de tocar nada, acostúmbrate a mirar el estado actual y a dejar “migajas de pan” para volver atrás.
- Revisar antes y después:
git status,git log --oneline --decorate -n 10 - Ver qué cambió exactamente:
git diff(sin staging) ygit diff --staged(en staging) - Marca un punto seguro (opcional):
git branch backup/antes-de-arreglar
Mapa de decisiones (rápido)
| Situación | Objetivo | Comando recomendado | Riesgo |
|---|---|---|---|
| No he commiteado | Quitar cambios del working tree o del staging | git restore / git restore --staged | Bajo (si revisas diff) |
| Comité pero no publiqué | Rehacer commits locales (mover HEAD) | git reset --soft|--mixed|--hard | Medio (hard puede perder cambios no guardados) |
| Comité y publiqué | Deshacer sin reescribir historial compartido | git revert | Bajo (crea commit inverso) |
| Último commit tiene error (y no publiqué) | Corregir contenido o mensaje del último commit | git commit --amend | Bajo/medio (no usar si ya publicaste) |
| Necesito editar mensajes antiguos | Reescribir mensajes de commits anteriores | git rebase -i (solo local) | Alto si ya está publicado |
Escenario 1: “No he commiteado” (working tree y staging)
1) Deshacer cambios en archivos (sin afectar commits)
Si modificaste un archivo pero quieres volver a la versión del último commit:
git status
git diff
git restore ruta/al/archivoPara descartar todos los cambios no commiteados del directorio de trabajo:
git restore .Advertencia: esto descarta cambios locales. Revisa antes con git diff.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
2) Sacar un archivo del staging (pero conservar cambios)
Si hiciste git add por error:
git status
git diff --staged
git restore --staged ruta/al/archivoEsto mueve el archivo fuera del staging, pero mantiene las modificaciones en tu directorio de trabajo.
Escenario 2: “Comité pero no publiqué” (reset: soft/mixed/hard)
git reset mueve el puntero de tu rama (HEAD) a otro commit. La diferencia entre --soft, --mixed y --hard es qué hace con el staging y el directorio de trabajo.
| Modo | HEAD | Staging (index) | Working tree | Uso típico |
|---|---|---|---|---|
--soft | Se mueve | Se conserva | Se conserva | “Quiero rehacer el commit, pero mantener todo listo para commitear” |
--mixed (por defecto) | Se mueve | Se limpia | Se conserva | “Quiero volver a antes del commit y revisar qué agregar” |
--hard | Se mueve | Se limpia | Se descarta | “Quiero tirar todo y volver exactamente al commit” |
Guía paso a paso: “Hice un commit, pero quiero editarlo o dividirlo”
Supón que tu historial local tiene:
git log --oneline -n 3
f3a1c2d (HEAD -> feature) Agrega validación
9b12aa0 Ajusta estilos
1c0ffee InicioQuieres deshacer el último commit, pero conservar los cambios para rearmarlos.
Opción A: reset --soft (mantiene staging)
git reset --soft HEAD~1
git statusAhora los cambios quedan en staging como si el commit no hubiera ocurrido. Puedes:
git commit -m "Agrega validación (parte 1)"Opción B: reset --mixed (mantiene cambios, pero fuera de staging)
git reset HEAD~1
git status
git diffAhora decides qué archivos agregar:
git add archivo1
git commit -m "Agrega validación en formulario"
git add archivo2
git commit -m "Agrega mensajes de error"Opción C: reset --hard (descarta todo)
git reset --hard HEAD~1Advertencia: perderás cambios no guardados en commits. Úsalo solo si estás seguro (o si ya tienes un respaldo/branch temporal).
Escenario 3: “Comité y publiqué” (revert: la opción segura)
Cuando un commit ya está en una rama compartida (por ejemplo, ya hiciste push), lo más seguro es git revert. En lugar de borrar o reescribir commits, crea un nuevo commit que invierte los cambios. Así, el historial sigue siendo lineal y coherente para todos.
Revertir un commit específico
1) Identifica el commit:
git log --oneline --decorate -n 102) Revierte:
git revert <hash_del_commit>3) Verifica:
git status
git log --oneline -n 54) Publica el revert:
git pushRevertir un merge commit (caso común en ramas compartidas)
Si necesitas revertir un merge, Git requiere que indiques el “mainline” (normalmente -m 1 si la primera rama es la principal):
git revert -m 1 <hash_del_merge>Si no estás seguro, revisa el merge en el log con más detalle:
git show <hash_del_merge>Revertir varios commits
Para revertir un rango (por ejemplo, los últimos 3 commits), puedes revertirlos uno por uno o usar un rango. Una forma controlada es revertir sin commitear y luego crear un solo commit:
git revert --no-commit HEAD~3..HEAD
git status
git commit -m "Revierte cambios problemáticos de validación"
git pushNota: si hay conflictos durante el revert, resuélvelos y continúa con git revert --continue.
Corregir el último commit: amend (sin publicar)
git commit --amend reemplaza el último commit por uno nuevo, combinando el contenido actual del staging (y opcionalmente cambios del working tree si los agregas) y permitiéndote editar el mensaje. Esto reescribe el historial, así que úsalo cuando el commit no se haya publicado.
Amend para corregir el mensaje del último commit
git commit --amendSe abrirá tu editor para modificar el mensaje.
Amend para agregar archivos olvidados al último commit
git status
git add archivo_que_olvide
git commit --amendVerifica el resultado:
git log --oneline -n 2Amend sin cambiar el mensaje
git add archivo_que_olvide
git commit --amend --no-editAdvertencia: si ya hiciste push del commit original, no uses amend en esa rama compartida. En ese caso, crea un commit nuevo o usa revert si necesitas deshacer.
Editar mensajes antiguos (solo si NO está compartido)
Si necesitas corregir el mensaje de un commit que no es el último, la herramienta típica es el rebase interactivo. Esto reescribe hashes de commits, por lo que no debe aplicarse sobre historial ya publicado (a menos que el equipo lo coordine explícitamente).
Cambiar el mensaje de un commit antiguo
1) Abre un rebase interactivo de los últimos N commits (elige N para incluir el commit a editar):
git log --oneline -n 10
git rebase -i HEAD~52) En el editor, cambia pick por reword en el commit cuyo mensaje quieres editar.
pick a1b2c3d Agrega validación
reword 9b12aa0 Ajusta estilos
pick 1c0ffee Inicio3) Guarda y cierra. Git te pedirá el nuevo mensaje. Al finalizar:
git log --oneline -n 5Si el commit ya estaba en remoto: evita esto. Alternativas seguras: (1) dejar el mensaje como está, (2) agregar un commit nuevo que aclare, (3) revert si el problema es el contenido.
Prácticas de seguridad: inspección y recuperación con reflog
Checklist antes/después de “deshacer”
- Antes:
git status,git log --oneline --decorate -n 10,git diff - Después: repite los mismos comandos para confirmar que estás donde querías.
- Si vas a usar
reset --hard: considera crear un branch de respaldo:git branch backup/mi-punto
Recuperar estados perdidos con git reflog
git reflog registra a dónde apuntó HEAD recientemente, incluso si moviste la rama con reset o rebase. Es tu “caja negra” para recuperar commits “perdidos”.
1) Mira el reflog:
git reflogVerás entradas como:
c0ffee1 HEAD@{0}: reset: moving to HEAD~1
f3a1c2d HEAD@{1}: commit: Agrega validación2) Vuelve a un estado anterior (por hash o por referencia HEAD@{n}):
git reset --hard f3a1c2do
git reset --hard HEAD@{1}3) Confirma:
git log --oneline -n 5
git statusConsejo: si no quieres mover tu rama todavía, puedes crear un branch desde el estado recuperado:
git branch recuperacion f3a1c2dResumen operativo: qué usar según el contexto
- Rama compartida (ya publicaste): usa
git revertpara deshacer con un commit inverso; evitareset,amendy rebase interactivo. - Trabajo local (no publicaste): usa
git resetpara mover HEAD (soft/mixed/hard según necesites conservar staging/working tree). - Último commit local con detalles a corregir: usa
git commit --amend. - Mensajes antiguos (solo local): usa
git rebase -iconreword. - Si algo sale mal: consulta
git reflogy vuelve a un estado anterior.