git reset
Restablecer el HEAD actual al estado indicado
El comando 'git reset' sirve para deshacer cambios moviendo el HEAD de la rama actual a un commit concreto. Tiene tres modos principales: --soft (conserva los cambios preparados), --mixed (por defecto: conserva los cambios en el directorio de trabajo) y --hard (descarta todos los cambios). Es esencial para deshacer commits, quitar archivos de la preparación y gestionar tu historial. Cuidado con 'git reset --hard', que descarta los cambios para siempre.
Sinopsis
git reset [-q] [<tree-ish>] [--] <pathspec>...
git reset [-q] [--pathspec-from-file=<file>] [<tree-ish>]
git reset (--patch | -p) [<tree-ish>] [--] [<pathspec>...]
git reset [--soft | --mixed [-N] | --hard | --merge | --keep] [-q] [<commit>]Opciones
Elegir la opción adecuada
Modos de reset: ¿qué se conserva?
Entender los tres modos principales de reset y qué pasa con tus cambios
| Comando | HEAD se mueve | Área de preparación | Directorio de trabajo | Úsalo cuando |
|---|---|---|---|---|
--soft | Sí | Se conservan (preparados) | Conservado | Deshacer un commit para rehacerlo con cambios |
--mixed (default) | Sí | Se vacía (sin preparar) | Conservado | Deshacer un commit para editar antes de preparar |
--hard | Sí | Vaciado | Se PIERDEN los cambios con seguimiento (los sin seguimiento se quedan) | Descartar por completo el commit y todos los cambios |
Reset frente a revert y checkout
Elegir el comando adecuado para deshacer según tu situación
| Comando | ¿Modifica el historial? | ¿Seguro con commits subidos? | Ideal para |
|---|---|---|---|
git reset | Sí (mueve la rama) | No: causa problemas | Deshacer commits locales aún sin subir |
git revert | No (añade un commit nuevo) | Sí: seguro en ramas compartidas | Deshacer commits subidos en ramas compartidas |
git checkout -- file | No | Sí | Descartar cambios sin commit de archivos concretos |
Quitar cambios de la preparación: reset frente a restore
El Git moderno ofrece git restore como alternativa a reset para quitar de la preparación
| Comando | Propósito | ¿Afecta a los commits? | Recomendado |
|---|---|---|---|
git reset HEAD file | Quitar un archivo de la preparación | No | Forma tradicional |
git restore --staged file | Quitar un archivo de la preparación | No | Forma moderna (Git 2.23+) |
git reset | Quitar todos los archivos de la preparación | No | Funciona bien |
git restore --staged . | Quitar todos los archivos de la preparación | No | Intención más explícita |
Modos de reset avanzados
Cuándo usar --merge y --keep en lugar de --hard
| Comando | ¿Conserva los cambios locales? | ¿Se detiene si hay conflictos? | Caso de uso |
|---|---|---|---|
--hard | No: lo destruye todo | No | Reset completo, los cambios dan igual |
--merge | Solo los cambios sin preparar (los preparados se pierden) | Sí | Cancelar un merge conservando el trabajo no relacionado |
--keep | Sí (en los archivos que el reset no toca) | Sí | Deshacer un commit pero conservar cambios locales no relacionados |
Ejemplos
Deshacer el último commit y conservar los cambios preparados
git reset --soft HEAD~1Retrocede HEAD un commit. Los cambios de ese commit siguen preparados, listos para un nuevo commit.
Deshacer el último commit y conservar los cambios en el directorio de trabajo
git reset HEAD~1Modo por defecto (--mixed). Retrocede HEAD un commit. Los cambios se conservan, pero sin preparar.
Descartar por completo el último commit y los cambios
git reset --hard HEAD~1Retrocede HEAD un commit y descarta TODOS los cambios sin commit de los archivos con seguimiento. Con cuidado: el trabajo sin commit perdido no se puede recuperar (el commit en sí sigue en git reflog).
Quitar de la preparación un archivo concreto
git reset HEAD file.jsQuita file.js del área de preparación sin descartar los cambios. El archivo sigue modificado en el directorio de trabajo.
Ejemplos de flujos de trabajo
git log --oneline -3Ver los commits recientes para confirmar cuál deshacer
git reset --soft HEAD~1Deshacer el commit y conservar los cambios preparados
git statusComprobar que los cambios están preparados
git commit -m "Better message"Volver a hacer commit con un mensaje nuevo
git statusVer qué está preparado ahora
git reset HEAD unwanted-file.jsQuitar de la preparación uno o varios archivos
git statusComprobar que el archivo ya no está preparado
git commitHacer commit solo de los archivos que quieres
git statusRevisar lo que se va a perder
git stash(Opcional) Guardar los cambios por si acaso
git reset --hard HEAD~1Descartar el último commit Y todos los cambios con seguimiento (los archivos sin seguimiento se quedan)
git statusComprobar que el directorio de trabajo está limpio
git reflogEncontrar el hash del commit anterior al reset
git reset --hard abc1234Volver a ese hash de commit
git log --onelineComprobar que los commits se han recuperado
Solución de problemas
fatal: ambiguous argument 'HEAD~1': unknown revision
Causa: Estás en el commit inicial: no hay un commit anterior al que volver
Revisa git log. Si solo hay un commit, no puedes retroceder más. Usa git update-ref -d HEAD para empezar de cero por completo.
error: Entry 'app.js' not uptodate. Cannot merge.
Causa: Un archivo que --merge o --keep tendría que cambiar tiene ediciones locales sin commit, así que el reset se cancela
Haz commit o stash de tus cambios primero, o usa --hard si quieres descartarlos
Usé --hard sin querer y perdí cambios
Causa: El reset hard descarta para siempre todo el trabajo sin commit
Si los cambios tenían commit: git reflog para encontrar el commit y luego git reset --hard <hash>. Si nunca tuvieron commit: probablemente se han perdido para siempre.
El reset funcionó, pero un compañero dice que el historial está roto
Causa: Hiciste reset de commits que ya estaban subidos a una rama compartida
En ramas compartidas, usa git revert. Para arreglarlo: git reflog, encuentra el commit original, haz reset a él y luego force push (coordínate con el equipo).
fatal: ambiguous argument 'HEAD' al ejecutar git reset HEAD file
Causa: El repositorio aún no tiene commits, así que HEAD no existe (o la ruta es incorrecta)
Quita HEAD: git reset file.js (o git rm --cached file.js). Comprueba la ruta exacta con git status.
Consejos y trampas
Buenas prácticas
- ✓Nunca uses git reset con commits subidos a ramas compartidas: usa git revert en su lugar
- ✓Ejecuta siempre git status antes de un reset para entender qué se verá afectado
- ✓Mejor --soft cuando quieras rehacer un commit con cambios
- ✓Haz git stash antes de un reset --hard si quizá quieras recuperar tus cambios
- ✓Recuerda que git reflog permite recuperarse de la mayoría de errores de reset (para cambios con commit)
- ✓Usa git reset HEAD <file> para quitar archivos de la preparación en lugar de hacer reset de commits enteros
- ✓Plantéate git restore --staged como alternativa moderna para quitar archivos de la preparación
Errores comunes
- ✗Usar 'git reset --hard' sin darse cuenta de que borra para siempre los cambios sin commit. Compruébalo siempre dos veces antes de usar --hard.
- ✗Hacer reset de commits ya subidos a un remoto compartido. Reescribe el historial y causa problemas a quienes colaboran. Usa 'git revert' en su lugar.
- ✗Confundir 'git reset' con 'git revert'. Reset mueve hacia atrás el puntero de la rama; revert crea un commit nuevo que deshace los cambios.
- ✗No saber que puedes recuperarte de un mal reset usando 'git reflog' para encontrar el hash del commit anterior.
- ✗Usar 'git reset --hard HEAD' para descartar cambios de trabajo cuando 'git checkout -- .' o 'git restore .' serían más adecuados.
Preguntas frecuentes
Soft conserva los cambios preparados. Mixed (por defecto) los conserva en el directorio de trabajo, pero sin preparar. Hard lo descarta todo. Piénsalo así: soft = deshacer solo el commit, mixed = deshacer el commit + quitar de la preparación, hard = deshacerlo todo.
Para cambios con commit: sí, usa git reflog para encontrar el hash del commit original y haz reset a él. Para cambios sin commit perdidos con --hard: normalmente no, han desaparecido para siempre.
HEAD~1 significa «un commit antes de HEAD». HEAD~2 son dos commits atrás, etc. También puedes usar directamente hashes de commit, como git reset abc1234.
Reset para commits locales aún sin subir: reescribe el historial de forma limpia. Revert para commits subidos en ramas compartidas: crea un commit nuevo que deshace los cambios sin reescribir el historial.
Usa git reset HEAD filename para quitar un archivo concreto de la preparación. No mueve HEAD ni afecta a ningún commit: solo saca el archivo del área de preparación.
Borra para siempre los cambios sin commit. A diferencia de los cambios con commit (recuperables con el reflog), el trabajo que nunca tuvo commit no se puede recuperar tras un reset hard.