Git: switch, restore, reset y revert
Guía práctica y técnica para cambiar de ramas, recuperar archivos, deshacer commits y reparar errores sin destruir el historial.
Git permite realizar prácticamente cualquier operación sobre el historial de un proyecto, pero precisamente por eso algunos comandos pueden resultar peligrosos si no se entiende exactamente qué referencia, archivo o estado están modificando.
Cuatro comandos permiten separar claramente diferentes tipos de operaciones que durante años estuvieron concentradas principalmente en git checkout:
git switch→ trabajar con ramas y HEAD.git restore→ trabajar con archivos, staging y working tree.git reset→ mover referencias y, según el modo utilizado, modificar el staging y el working tree.git revert→ crear nuevos commits que deshacen cambios anteriores.
Guía rápida: ¿qué comando necesitas ahora?
¿Quieres cambiar de rama?
→ git switch
¿Quieres crear una rama?
→ git switch -c nombre-rama
¿Quieres descartar cambios locales de un archivo?
→ git restore archivo
¿Quieres quitar un archivo del staging sin perder sus cambios?
→ git restore --staged archivo
¿Quieres recuperar un archivo de otro commit?
→ git restore --source COMMIT -- archivo
¿Quieres eliminar commits locales antes de hacer push?
→ git reset
¿Quieres deshacer un commit que ya está publicado?
→ git revert
¿Has hecho un reset y necesitas recuperar el estado anterior?
→ git reflog
¿Por qué necesitas dominar estos comandos?
Los problemas reales con Git rara vez aparecen cuando todo funciona correctamente. Aparecen cuando necesitas recuperar algo, deshacer un cambio o reparar una situación que ya ha llegado al repositorio remoto.
Aquí no basta necesariamente con borrar el archivo del proyecto. Si las credenciales quedaron registradas en el historial, siguen formando parte del repositorio y deben considerarse comprometidas.
En este caso probablemente no quieres modificar el historial. Solo necesitas inspeccionar una versión anterior o recuperar determinados archivos.
Si el commit ya está publicado y otros desarrolladores trabajan sobre él, normalmente la solución adecuada es git revert, no reescribir la historia con git reset.
Aquí git reset puede ser exactamente la herramienta adecuada, especialmente si esos commits todavía no han sido compartidos.
Antes de tocar nada: entiende los estados de Git
Para entender switch, restore, reset y revert es necesario distinguir las diferentes partes del estado de un repositorio.
| Zona | Qué contiene | Ejemplo |
|---|---|---|
| HEAD | Referencia al commit actualmente comprobado. Cuando estás sobre una rama, normalmente HEAD apunta a esa rama. | HEAD -> main |
| Staging Area / Index | Estado de los archivos que se utilizará para construir el próximo commit. | git add archivo.js |
| Working Tree | Los archivos que tienes físicamente en tu directorio de trabajo. | Archivos modificados localmente |
Una forma sencilla de visualizar la relación:
HEAD
│
▼
COMMIT
│
▼
STAGING AREA
│
▼
WORKING TREE
Muchos errores con Git ocurren porque se utiliza un comando pensando que afecta a una zona cuando en realidad afecta a otra.
Git Switch: cambiar y crear ramas
git switch está diseñado específicamente para trabajar con ramas y HEAD.
¿Cuándo utilizarlo?
- Para cambiar a una rama existente.
- Para crear una rama nueva.
- Para crear una rama a partir de otra referencia.
- Para volver rápidamente a la rama anterior.
- Para inspeccionar un commit mediante detached HEAD.
Cambiar a una rama existente
git switch developCambia la rama actual a
develop.
La operación equivalente con checkout sería:
git checkout develop
git switch deja más clara la intención: quiero cambiar de rama.
Crear una rama y cambiar a ella
git switch -c nueva-featureCrea
nueva-feature desde la posición actual y cambia a ella.
Equivalente:
git checkout -b nueva-feature
Crear una rama desde una referencia concreta
git switch -c hotfix v1.4.2Crea
hotfix partiendo del tag v1.4.2.
Esto resulta especialmente útil cuando necesitas preparar una corrección partiendo exactamente de una versión publicada.
Volver a la rama anterior
git switch -Vuelve a la rama en la que estabas anteriormente.
git switch main
# trabajo...
git switch develop
# trabajo...
git switch -
# vuelve a main
Detached HEAD
git switch --detach abc123Coloca HEAD directamente sobre el commit
abc123.
Esto resulta útil para inspeccionar, ejecutar o probar una versión concreta sin mover ninguna rama.
git switch --detach abc123
git status
# HEAD detached at abc123
Si durante ese estado realizas commits y quieres conservarlos de forma permanente mediante una rama:
git switch -c investigacion-bug
Git Restore: recuperar y descartar archivos
git restore está diseñado principalmente para trabajar con el contenido de los archivos, tanto en el working tree como en el staging area.
Es especialmente útil cuando necesitas recuperar archivos o eliminar modificaciones locales.
Descartar cambios locales de un archivo
git restore archivo.jsRestaura el archivo utilizando el contenido del índice y descarta las modificaciones no staged del working tree.
git diff.
Comprobar antes de restaurar
git status
git diff
git restore archivo.js
Este pequeño hábito puede evitar muchos accidentes.
Descartar cambios de todos los archivos
git restore .Descarta las modificaciones no staged de los archivos afectados bajo la ruta actual.
No debería ejecutarse a ciegas en un proyecto con trabajo local importante.
git restore solo afecta a archivos trackeados. Los archivos nuevos no añadidos (untracked) no se tocan. Si además quieres eliminar archivos sin seguimiento (generados por builds, logs, etc.), usa git clean -fd con extrema precaución.
Quitar un archivo del staging
git restore --staged archivo.jsRetira el archivo del staging, pero mantiene sus modificaciones en el working tree.
git add archivo.js
git restore --staged archivo.js
El archivo deja de estar preparado para el commit, pero no se pierden sus cambios.
Recuperar un archivo desde un commit anterior
git restore --source abc123 -- archivo.jsRecupera la versión de
archivo.js existente en abc123 y la coloca en el working tree.
Este comando resulta especialmente útil cuando quieres rescatar un archivo concreto sin retroceder toda la rama.
git restore --source no coloca HEAD en detached HEAD. El comando modifica el contenido del archivo en tu working tree; la rama actual continúa siendo la misma.
Git Reset: mover una rama hacia atrás
git reset es conceptualmente diferente de git restore.
Mientras restore está orientado principalmente al contenido de archivos, reset puede mover la referencia de la rama y modificar el estado del staging y del working tree dependiendo de la opción utilizada.
Por eso debe utilizarse con más precaución.
Los tres modos principales
1. --soft
git reset --soft HEAD~1Mueve la referencia de la rama un commit hacia atrás y mantiene los cambios preparados en staging.
git commit -m "Commit incorrecto"
git reset --soft HEAD~1
# Los cambios siguen staged
git commit -m "Commit corregido"
git reset --soft HEAD~3Deshace los últimos 3 commits pero deja todos los cambios en el staging, permitiendo crear un único commit limpio.
# Tienes 3 commits feos y quieres fusionarlos en 1 antes de hacer push
git reset --soft HEAD~3
git commit -m "Feature completa y limpia"
2. --mixed
git reset HEAD~1Mueve la referencia de la rama y actualiza el staging, pero conserva los cambios en el working tree.
--mixed es el comportamiento predeterminado de git reset.
3. --hard
git reset --hard HEAD~3Mueve la rama y hace que el índice y el working tree coincidan con el commit de destino, descartando cambios que no estén en ese commit.
git reset --hard puede eliminar cambios locales no guardados. Además, si mueve una rama que ya ha sido compartida, puede provocar divergencias y requerir una reescritura del historial remoto.
¿Cuándo tiene sentido utilizar reset --hard?
Principalmente cuando estás trabajando en una rama local y tienes claro que quieres abandonar el estado actual.
git status
git log --oneline -5
git reset --hard HEAD~2
Antes de ejecutar el comando, asegúrate de que realmente quieres eliminar el estado actual.
Git Reflog: la red de seguridad
Uno de los mecanismos más importantes para recuperar estados aparentemente perdidos es:
git reflog
El reflog registra movimientos recientes de referencias locales, incluidos cambios producidos por operaciones como reset.
git reflog
abc1234 HEAD@{0}: reset: moving to HEAD~2
def5678 HEAD@{1}: commit: Añadir nueva API
987abcd HEAD@{2}: commit: Corregir autenticación
Si descubres que el reset fue un error, puedes localizar el estado anterior y recuperar la referencia:
git reset --hard def5678
git reflog -10Muestra las últimas 10 operaciones. Cada línea tiene un hash y un marcador tipo
HEAD@{n}. Elige el estado al que quieras volver y ejecuta git reset --hard HEAD@{n}.
# Ejemplo real
git reflog
# a1b2c3d HEAD@{5}: commit: Mensaje importante
# e4f5g6h HEAD@{6}: commit: Otro cambio
# Vuelves al estado de HEAD@{5}
git reset --hard a1b2c3d
Git Revert: deshacer sin reescribir el historial
git revert utiliza una estrategia completamente diferente.
En lugar de mover la rama hacia atrás, crea un nuevo commit que invierte los cambios introducidos por otro commit.
A --- B --- C
↑
HEAD
Si ejecutamos:
git revert C
Git crea otro commit:
A --- B --- C --- C'
↑
HEAD
C' contiene los cambios necesarios para deshacer el efecto de C.
push sin reescribir la historia de los demás desarrolladores.
Revertir el último commit
git revert HEADCrea un nuevo commit que invierte el último commit.
Revertir un commit concreto
git revert abc123Crea un commit que deshace los cambios introducidos por
abc123.
Revertir sin abrir el editor del mensaje
git revert --no-edit abc123Utiliza el mensaje generado automáticamente.
Revertir un rango de commits
git revert abc123..xyz789Solicita revertir los commits alcanzables desde
xyz789 pero no desde abc123.
A..B significa normalmente “alcanzables desde B pero no desde A”. Antes de revertir muchos commits conviene inspeccionar exactamente qué commits entran en el rango.
git log --oneline abc123..xyz789
Revert y conflictos
Un revert no siempre puede aplicarse automáticamente.
Si los cambios posteriores modificaron las mismas líneas que el commit que quieres revertir, Git puede producir un conflicto.
git revert abc123
# Si aparecen conflictos:
git status
# Resolver manualmente los archivos
git add archivo-resuelto.js
git revert --continue
Si decides cancelar la operación:
git revert --abort
Reset vs Revert: la diferencia fundamental
| Característica | reset |
revert |
|---|---|---|
| Qué hace | Mueve una referencia y puede modificar índice y working tree | Crea un nuevo commit que invierte cambios anteriores |
| Reescribe historia | Sí, cuando mueve una rama | No |
| Puede modificar el working tree | Sí, especialmente con --hard |
No directamente |
| Adecuado para commits publicados | Generalmente no | Sí |
| Genera un commit nuevo | No | Sí |
Switch vs Restore vs Reset vs Revert
| Comando | Propósito principal | Actúa principalmente sobre | Reescribe historial | Riesgo |
|---|---|---|---|---|
git switch |
Cambiar o crear ramas | HEAD / ramas | No | Bajo |
git restore |
Restaurar archivos | Working tree / staging | No | Bajo (si especificas archivo) / Medio-alto (si usas .) |
git reset |
Mover referencias | HEAD / staging / working tree | Sí, cuando mueve una rama | Medio-alto |
git revert |
Deshacer commits | Historial mediante nuevo commit | No | Bajo-medio |
Flujo de trabajo recomendado
Para cambiar de rama
# Con checkout
git checkout main
# Con switch
git switch main
Para crear una rama
# Con checkout
git checkout -b nueva-rama
# Con switch
git switch -c nueva-rama
Para restaurar un archivo
# Con checkout
git checkout -- archivo.js
# Con restore
git restore archivo.js
Para recuperar un archivo desde un commit
# Con checkout
git checkout abc123 -- archivo.js
# Con restore
git restore --source abc123 -- archivo.js
git checkout sigue existiendo y continúa siendo válido. git switch y git restore permiten expresar de forma más específica si la intención es trabajar con ramas o con archivos.
Un caso real: metí un archivo sensible en un commit
Supongamos que accidentalmente hiciste:
git add .
git commit -m "Configuración"
git push
y descubriste que habías incluido un archivo como:
.env
config/secrets.json
credentials.json
Eliminar el archivo en un commit posterior no hace que la credencial deje de existir en el historial anterior.
El procedimiento depende de si el commit se ha publicado y del tipo de secreto. En primer lugar:
git status
git log --oneline --all --decorate -10
git reset y git revert no eliminan el archivo del historial. La credencial seguirá accesible mediante el hash del commit. Para limpiar el historial de forma efectiva, necesitas herramientas como git filter-repo (recomendada oficialmente) o BFG Repo-Cleaner. Estas reescriben el historial eliminando el archivo sensible de todos los commits.
# Ejemplo con filter-repo (requiere instalación)
git filter-repo --path secrets.json --invert-paths
# O con BFG (alternativa)
bfg --delete-files secrets.json
Si el secreto es real, la prioridad debería ser revocar o rotar la credencial. Después se puede estudiar la limpieza del historial. En un repositorio compartido no conviene improvisar un reset --hard o un force-push sin la coordinación adecuada con el equipo.
Un caso real: necesito recuperar una versión anterior
Primero inspecciona el historial:
git log --oneline --decorate --graph --all
Si solo quieres examinar un commit:
git switch --detach abc123
Si quieres recuperar únicamente un archivo:
git restore --source abc123 -- archivo.js
Si quieres volver permanentemente la rama a un commit anterior y todavía estás trabajando localmente:
git reset --hard abc123
Son tres operaciones completamente diferentes, aunque las tres puedan aparecer en una situación de “quiero volver atrás”.
Un caso real: bug desplegado en producción
Imagina este historial:
A --- B --- C --- D
↑
commit con bug
Si D ya está en producción y forma parte de una rama compartida, normalmente quieres mantener el historial y crear un commit correctivo:
git revert D
El resultado conceptual:
A --- B --- C --- D --- R
↑
deshace D
Después puedes revisar, probar y publicar el nuevo commit:
git status
git push
Esto permite que todos los miembros del equipo vean exactamente qué ocurrió.
Buenas prácticas antes de ejecutar comandos destructivos
Antes de utilizar reset --hard, borrar cambios o manipular ramas, acostúmbrate a ejecutar:
git status
git branch --show-current
git log --oneline --decorate -10
git diff
Y si vas a manipular commits:
git reflog -10
Estas comprobaciones tardan segundos y pueden evitar perder horas de trabajo.
Regla de oro
Si el historial ya está compartido, piensa dos veces antes de reescribirlo.
Si el cambio solo existe localmente, tienes mucha más libertad para utilizar reset.
Si quieres modificar archivos, piensa en restore.
Si quieres cambiar de rama, piensa en switch.
Si quieres deshacer un commit publicado sin reescribir la historia, piensa en revert.
Tabla definitiva: ¿qué comando necesito?
| Problema | Comando recomendado |
|---|---|
| Cambiar de rama | git switch rama |
| Crear una rama | git switch -c rama |
| Volver a la rama anterior | git switch - |
| Inspeccionar un commit | git switch --detach COMMIT |
| Descartar cambios locales | git restore archivo |
| Descartar cambios de varios archivos | git restore . |
| Quitar del staging | git restore --staged archivo |
| Recuperar un archivo antiguo | git restore --source COMMIT -- archivo |
| Rehacer el último commit local | git reset --soft HEAD~1 |
| Fusionar varios commits locales (squash) | git reset --soft HEAD~N |
| Volver atrás conservando archivos modificados | git reset --mixed COMMIT |
| Eliminar estado local y volver a un commit | git reset --hard COMMIT |
| Recuperar un estado después de un reset | git reflog |
| Deshacer un commit publicado | git revert COMMIT |
Conclusión
La separación entre git switch y git restore permite distinguir con mayor claridad dos operaciones que históricamente podían realizarse mediante git checkout: trabajar con ramas y trabajar con archivos.
La forma de pensar en estos comandos puede resumirse así:
RAMAS → git switch
ARCHIVOS → git restore
REFERENCIAS → git reset
DESHACER → git revert
RECUPERAR → git reflog
Una vez entiendes esta separación, Git deja de parecer una colección arbitraria de comandos y empieza a comportarse como lo que realmente es: un sistema de objetos y referencias donde cada operación modifica una parte concreta del estado del repositorio.
Guárdala como referencia antes de ejecutar un comando destructivo. En Git, cinco segundos leyendo
git status pueden ahorrarte horas de recuperación.
Visitas: 18
Automation & Data Specialist | Web Development | Data Processing & Integration
