Deshacer Cambios en Git: reset, restore, revert Explicados
Git es un potente sistema de control de versiones que te permite rastrear cambios en tu base de código. Sin embargo, los errores ocurren y podrías necesitar deshacer cambios. Git proporciona varios comandos para ayudarte con esto, pero funcionan de manera muy diferente y afectan a tu repositorio de formas distintas. Comprender los matices entre git reset, git restore y git revert es crucial para gestionar eficazmente el historial de tu proyecto y corregir errores sin consecuencias no deseadas.
Este artículo desmitificará estos tres comandos, explicando su propósito, cómo funcionan y cuándo usar cada uno. Aprovecharemos la documentación oficial de Git y los patrones de uso comunes para proporcionar explicaciones claras y ejemplos prácticos. Al final de esta guía, estarás equipado para deshacer cambios con confianza, gestionar tus archivos preparados (staged) y mantener un historial de commits limpio y coherente.
Comprendiendo los Conceptos Centrales
Antes de sumergirnos en los comandos, es importante captar algunos conceptos de Git:
- Directorio de Trabajo (Working Directory): Los archivos que estás editando actualmente.
- Área de Preparación (Staging Area / Index): Un área de espera donde preparas los cambios antes de confirmarlos (
commit).git addmueve los cambios del directorio de trabajo al área de preparación. - Historial de Commits (Commit History): Una secuencia de instantáneas de tu proyecto a lo largo del tiempo, representadas por commits.
- HEAD: Un puntero al commit más reciente en tu rama actual.
Estos tres comandos interactúan principalmente con estas áreas para modificar o descartar cambios.
git restore: Para Descartar Cambios en el Directorio de Trabajo y el Área de Preparación
El comando git restore, introducido más recientemente en Git, está diseñado para la tarea sencilla de deshacer cambios en tu directorio de trabajo o para quitar archivos del área de preparación. Generalmente se considera más seguro e intuitivo para estas operaciones específicas que git reset.
Quitar Archivos del Área de Preparación (Unstaging Files)
Si has preparado accidentalmente un archivo usando git add y quieres quitarlo del área de preparación, git restore es el comando a usar. Mueve los cambios de vuelta desde el área de preparación a tu directorio de trabajo, pero no descarta las modificaciones en sí.
-
Quitar un archivo específico del área de preparación:
bash git restore <archivo>
Este comando toma la versión del archivo del índice (área de preparación) y la devuelve al índice. Esencialmente, elimina el archivo del área de preparación para el próximo commit, pero los cambios permanecen en tu directorio de trabajo. -
Quitar todos los archivos del área de preparación:
Si bien no existe ungit restore .directo para quitar todos los archivos del área de preparación de la misma manera quegit resetpuede hacerlo, típicamente aplicaríasgit restorea archivos individuales o lo usarías en conjunto con otros comandos si fuera necesario. Sin embargo, el caso de uso más común es quitar archivos específicos del área de preparación.
Descartar Cambios en el Directorio de Trabajo
git restore también se puede usar para descartar todos los cambios no preparados (unstaged) en tu directorio de trabajo para un archivo específico, revirtiéndolo a la versión en el área de preparación (índice) o al estado confirmado (committed) más reciente.
-
Descartar cambios no preparados en un archivo:
bash git restore <archivo>
(Nota: Este comando puede tener dos significados dependiendo del contexto. Cuando se usa sin--staged, se dirige principalmente al árbol de trabajo. Si el archivo está preparado, lo quita del área de preparación. Si el archivo está modificado en el árbol de trabajo y no está preparado, revierte el archivo del árbol de trabajo para que coincida con el índice.) -
Descartar cambios tanto preparados como no preparados para un archivo (revertir a HEAD):
Para descartar completamente todos los cambios (tanto preparados como no preparados) para un archivo y revertirlo al estado en el que estaba en el commitHEAD:
bash git restore --staged --worktree <archivo>
Este es un comando potente que efectivamente restablece el archivo a su último estado confirmado.
Restaurar un Archivo desde un Commit Específico
git restore también puede recuperar la versión de un archivo específico de un commit pasado sin alterar el historial de tu rama.
git restore <archivo> --source <commit>
Reemplaza <commit> con el hash del commit o una referencia simbólica como HEAD~1.
git reset: Reescribir el Historial
git reset es un comando más potente que puede modificar el historial de tu branch moviendo el puntero HEAD de la rama actual. También puede afectar al área de preparación y al directorio de trabajo, dependiendo del modo utilizado.
Comprendiendo los Modos (--soft, --mixed, --hard)
git reset tiene tres modos principales:
-
--soft: MueveHEADal commit especificado pero deja tu área de preparación y directorio de trabajo sin cambios. Los cambios de los commits restablecidos aparecen como cambios preparados (staged).
bash git reset --soft HEAD^ # Mueve HEAD un commit hacia atrás, los cambios del commit deshecho están preparados -
--mixed(por defecto): MueveHEADy restablece el área de preparación para que coincida con el commit especificado. Los cambios de los commits restablecidos están presentes en tu directorio de trabajo pero no están preparados.
bash git reset HEAD^ # Equivalente a git reset --mixed HEAD^ # Mueve HEAD un commit hacia atrás, los cambios del commit deshecho no están preparados -
--hard: MueveHEADy restablece tanto el área de preparación como el directorio de trabajo para que coincidan con el commit especificado. Esto descarta todos los cambios de los commits que se están restableciendo y cualquier cambio no confirmado posterior en el directorio de trabajo. Úsese con extrema precaución.
bash git reset --hard HEAD~ # Descarta el último commit Y todos los cambios desde entonces en el directorio de trabajo y el área de preparación
Casos de Uso para git reset:
- Quitar archivos del área de preparación:
git reset <archivo>es un atajo paragit restore --staged <archivo>, eliminando un archivo del área de preparación sin afectar el directorio de trabajo. - Quitar todos los archivos preparados:
git reset(sin argumentos o especificandoHEAD) quita todos los cambios actualmente preparados, moviéndolos de vuelta al directorio de trabajo (equivalente agit restore --staged .). - Deshacer el último commit:
git reset HEAD^(ogit reset --soft HEAD^) se usa comúnmente para modificar el último commit. Los cambios del commit anterior ahora están preparados, listos para ser confirmados nuevamente con modificaciones o un nuevo mensaje. - Descartar todos los cambios locales:
git reset --hardse usa para descartar completamente todas las modificaciones locales (preparadas y no preparadas) y revertir el repositorio a un commit específico. Esta es una operación destructiva.
Restablecer un Commit Antiguo
Si necesitas deshacer cambios de un commit que no es el más reciente, se puede usar git reset. Por ejemplo, para restablecer a un commit antes de uno problemático:
# Ejemplo: Deshacer los últimos 2 commits, manteniendo los cambios sin preparar
git reset --mixed HEAD~2
Advertencia: git reset reescribe el historial. Si ya has subido (push) los commits que estás restableciendo, esto puede causar problemas significativos para los colaboradores. Generalmente es seguro restablecer commits que solo existen en tu repositorio local.
git revert: Creando un Nuevo Commit para Deshacer Cambios
git revert es la forma más segura de deshacer cambios en un historial compartido o publicado. En lugar de reescribir el historial, crea un nuevo commit que introduce los cambios inversos de un commit anterior.
Cómo Funciona
Cuando ejecutas git revert <commit>, Git analiza el commit especificado, calcula los cambios opuestos y los aplica a tu directorio de trabajo y área de preparación actuales. Luego te pide crear un nuevo commit con un mensaje por defecto que indica qué commit se está revirtiendo.
-
Revertir un commit específico:
bash git revert <hash-del-commit>
Esto creará un nuevo commit que deshace los cambios introducidos por<hash-del-commit>. Si hay conflictos de fusión (merge conflicts), Git se pausará y requerirá que los resuelvas antes de hacer el commit. -
Revertir Múltiples Commits:
Puedes revertir un rango de commits:
bash # Revertir commits desde HEAD~3 hasta (pero sin incluir) HEAD git revert HEAD~3..HEAD
Git intentará crear un commit de reversión por cada commit especificado. Si surgen conflictos durante el proceso, necesitarás resolverlos para cada reversión.
Ventajas de git revert:
- Preserva el Historial: No altera los commits existentes, lo que lo hace seguro para ramas públicas o compartidas.
- Rastro de Auditoría Claro: El commit de reversión indica explícitamente qué se deshizo y por qué.
- Maneja Fusiones con Gracia: Git a menudo puede revertir commits de fusión automáticamente, aunque puede ser necesaria una intervención manual para escenarios complejos.
Cuándo Usar git revert:
- Cuando necesites deshacer cambios en una rama que ya ha sido subida (
push) a un repositorio remoto. - Cuando quieras mantener un registro claro e inmutable de todos los cambios, incluidas las correcciones.
- Al deshacer un commit de fusión (
merge commit).
Eligiendo el Comando Correcto
Aquí tienes una guía sencilla para ayudarte a decidir:
- Para quitar un archivo del área de preparación: Usa
git restore <archivo>ogit reset <archivo>. - Para descartar cambios no preparados en tu directorio de trabajo para un archivo: Usa
git restore <archivo>. - Para descartar todos los cambios (preparados y no preparados) para un archivo: Usa
git restore --staged --worktree <archivo>. - Para deshacer el último commit y mantener los cambios preparados (para modificación): Usa
git reset --soft HEAD^. - Para deshacer el último commit y mantener los cambios sin preparar: Usa
git reset HEAD^. - Para descartar completamente el último commit y todos los cambios subsiguientes (destructivo): Usa
git reset --hard HEAD^. - Para deshacer un commit en una rama compartida sin reescribir el historial: Usa
git revert <hash-del-commit>. - Para descartar todos los cambios locales en todo el repositorio (destructivo): Usa
git reset --hard.
Conclusión
Dominar git reset, git restore y git revert es fundamental para un uso eficaz de Git. git restore es tu opción principal para descartar cambios de forma segura en el directorio de trabajo y el área de preparación. git reset ofrece potentes capacidades de reescritura de historial, que es mejor usar en commits locales no subidos. git revert proporciona un método seguro y que preserva el historial para deshacer cambios, especialmente crucial en entornos colaborativos. Al comprender sus comportamientos distintos y elegir el comando apropiado, puedes gestionar con confianza la evolución de tu proyecto y corregir cualquier error en el camino.