Deshacer cambios sin miedo
Casi todo en Git se puede deshacer. La clave es saber dónde está lo que querés deshacer (sin preparar, preparado, commiteado o ya subido) y elegir el comando adecuado. Esta página empieza con una tabla para decidir.
Términos de esta página
- Descartar
- Tirar cambios que no commiteaste. Lo descartado que nunca estuvo en un commit no se puede recuperar.
- HEAD~1
- “El commit anterior a donde estoy”.
HEAD~2es dos atrás, y así. También se puede usar un hash:a1f3c9e. - restore
- Devuelve archivos a como estaban en el último commit (o en el que indiques). No toca el historial.
- reset
- Mueve la rama hacia atrás, a un commit anterior. Según el modo, los cambios de los commits “sacados” quedan preparados, sin preparar o se pierden.
- revert
- Crea un commit nuevo que hace lo contrario de otro. No borra nada del historial: es la forma segura de deshacer algo ya subido.
- amend
- Reemplazar el último commit por uno corregido.
- Reescribir el historial
- Cambiar o quitar commits que ya existen (
amend,reset,rebase). Está bien en commits locales; es problemático en commits ya subidos que otros usan. - reflog
- Un registro local de todos los lugares por donde pasó HEAD. Permite recuperar commits que parecen perdidos.
¿Qué comando uso?
Tabla de decisión
| Quiero… | Comando | ¿Se pierde algo? | ¿Sirve si ya hice push? |
|---|---|---|---|
| Descartar los cambios de un archivo | git restore archivo | Sí, esos cambios | — (no hay commit) |
| Sacar un archivo del área de preparación | git restore --staged archivo | No | — |
| Corregir el mensaje del último commit o sumarle un archivo | git commit --amend | No | No |
| Deshacer el último commit pero conservar los cambios | git reset --soft HEAD~1 | No | No |
| Volver la rama a un commit y tirar todo lo posterior | git reset --hard <hash> | Sí | No |
| Deshacer un commit que ya está en GitHub | git revert <hash> | No (queda en el historial) | Sí |
| Recuperar un archivo como estaba en un commit viejo | git restore --source <hash> archivo | Los cambios actuales de ese archivo | Sí |
| Recuperar un commit que “se perdió” tras un reset | git reflog + git reset --hard <hash> | No | — |
| Borrar archivos nuevos que no están en Git | git clean -n y luego -f | Sí | — |
Ante la duda, antes de algo destructivo, hacé una rama de respaldo: git branch respaldo. Si algo sale mal, tus commits siguen ahí.
Cambios que todavía no commiteaste
Descartar modificaciones
git restore app.jsapp.js a como estaba en el último commit. Lo que habías cambiado se pierde.git restore .git clean).Lo descartado con restore no pasa por ninguna papelera. Si no estás seguro, primero git stash (lo guarda) en vez de descartarlo.
Despreparar y limpiar
git restore --staged app.jsgit add: el archivo deja de estar preparado, pero tus cambios siguen en el archivo.git clean -ngit clean -f-d incluye carpetas. Los ignorados por .gitignore no se tocan (salvo con -x).Arreglar el último commit
Solo si todavía no hiciste push de ese commit.
Me equivoqué en el mensaje
git commit --amend -m "Mensaje correcto"push.Me olvidé un archivo
git add archivo-olvidado.js
git commit --amend --no-edit--no-edit conserva el mensaje que ya tenía. Igual que antes: solo si no hiciste push.Quiero “descommitear”
git reset --soft HEAD~1¿Ya lo subiste? Entonces no reescribas: usá git revert.
reset y sus tres modos
git reset <commit> mueve la rama actual hacia atrás. Los commits que quedan “después” dejan de estar en la rama. La pregunta es qué pasa con los cambios que tenían esos commits: eso lo decide el modo.
git reset --soft HEAD~1HEAD~1 = “uno antes del actual”; HEAD~3, tres) pero deja sus cambios preparados, listos para volver a commitear. Sirve para juntar varios commits en uno o rehacerlo con otro mensaje.git reset HEAD~1--soft ni --hard): deshace el commit y deja sus cambios en los archivos, pero sin preparar. Así podés elegir de nuevo con git add qué va en cada commit.git reset --hard origin/maingit fetch). ⚠ Se pierden los commits locales no subidos y los cambios sin commitear.--hard es el único comando habitual que borra trabajo sin commitear de forma irrecuperable. Corré git status antes.
revert: deshacer algo que ya subiste
Si el commit ya está en GitHub, no lo borres: otras personas (o Netlify) pueden tenerlo. git revert crea un commit nuevo que aplica lo contrario: si el original agregó una línea, el revert la quita. El historial queda completo y se ve qué se deshizo y cuándo.
git log --onelinegit revert a1f3c9egit pushgit push como cualquier otro, sin reescribir el historial. Por eso revert es la forma segura de deshacer algo que ya está en GitHub.- Si el revert choca con cambios posteriores, aparece un conflicto: se resuelve igual que en un merge y se sigue con
git revert --continue. git revert HEADdeshace el último commit.- Para revertir un commit de merge hay que indicar qué lado conservar:
git revert -m 1 <hash>(el lado 1 es la rama en la que estabas al hacer el merge).
Recuperar algo “perdido” con reflog
Hiciste un reset --hard de más, borraste una rama o un rebase salió mal. Mientras los cambios hayan estado commiteados, casi seguro se pueden recuperar: Git guarda en el reflog cada lugar por donde pasó HEAD durante los últimos meses.
git reflogHEAD se movió: commits, resets, cambios de rama, merges. Lista los movimientos del más nuevo al más viejo, con el hash de cada punto. Permite encontrar commits que ya no aparecen en git log. Se conserva unos 90 días.b7e10c2 HEAD@{0}: reset: moving to HEAD~1
9f2d4aa HEAD@{1}: commit: Agrega la ruta /health
b7e10c2 HEAD@{2}: commit: Corrige el puerto
Acá, el commit “Agrega la ruta /health” (9f2d4aa) es el que se perdió con el reset.
git reset --hard 9f2d4aagit status antes.git branch rescate 9f2d4aaEl reflog es solo local: no se sube a GitHub ni existe en otro clon.
Trabajar con versiones viejas
Recuperar un archivo de un commit
git restore --source a1f3c9e app.jsapp.js como estaba en ese commit (el resto del proyecto no cambia). Después lo commiteás si te sirve.git show a1f3c9e:app.jsMirar el proyecto entero en el pasado
git switch --detach a1f3c9egit switch maingit switch -c nombre.No encontré resultados.