Deshacer commits y cambios
En esta sección, abordaremos las estrategias y los comandos de Git que hay disponibles para deshacer acciones. Cabe destacar que Git no cuenta con un sistema tradicional para deshacer acciones como los de una aplicación de procesamiento de textos. Lo mejor es no relacionar las operaciones de Git con ningún modelo mental convencional al respecto. Además, Git tiene su propia nomenclatura para este tipo de operaciones, pero dejaremos este tema para otra ocasión. Esta nomenclatura incluye términos como “reset”, “revert”, “checkout” y “clean”, entre otros.
Una metáfora divertida consiste concebir Git como una utilidad de gestión de cronogramas. Las confirmaciones son instantáneas de un punto en el tiempo o puntos de interés a lo largo del cronograma del historial de un proyecto. Asimismo, se pueden gestionar varios cronogramas mediante ramas. Al deshacer una acción en Git, normalmente bien retrocedes en el tiempo o bien a otro cronograma en el que no se produjeron errores.
En este tutorial se ofrecen todas las habilidades necesarias para trabajar con las revisiones previas de un proyecto de software. En primer lugar, se muestra cómo explorar las confirmaciones antiguas. A continuación, se explica la diferencia que existe entre revertir confirmaciones públicas en el historial del proyecto y restablecer cambios no publicados en tu máquina local.
Encontrar lo que se ha perdido: revisar confirmaciones antiguas
La idea que se esconde tras cualquier sistema de control de versiones es almacenar copias “seguras” de un proyecto para no tener que preocuparte nunca sobre si se producen daños irreparables en tu base de código. Una vez que has creado un historial de confirmaciones del proyecto, puedes revisar y volver a consultar cualquier confirmación en el historial. Una de las mejores utilidades para revisar el historial de un repositorio de Git es el comando git log
. En el ejemplo que se muestra a continuación, hemos utilizado el comando git log para pasar una lista de las confirmaciones más recientes a una popular biblioteca de gráficos de código abierto.
git log --oneline
e2f9a78fe Replaced FlyControls with OrbitControls
d35ce0178 Editor: Shortcuts panel Safari support.
9dbe8d0cf Editor: Sidebar.Controls to Sidebar.Settings.Shortcuts. Clean up.
05c5288fc Merge pull request #12612 from TyLindberg/editor-controls-panel
0d8b6e74b Merge pull request #12805 from harto/patch-1
23b20c22e Merge pull request #12801 from gam0022/improve-raymarching-example-v2
fe78029f1 Fix typo in documentation
7ce43c448 Merge pull request #12794 from WestLangley/dev-x
17452bb93 Merge pull request #12778 from OndrejSpanel/unitTestFixes
b5c1b5c70 Merge pull request #12799 from dhritzkiv/patch-21
1b48ff4d2 Updated builds.
88adbcdf6 WebVRManager: Clean up.
2720fbb08 Merge pull request #12803 from dmarcos/parentPoseObject
9ed629301 Check parent of poseObject instead of camera
219f3eb13 Update GLTFLoader.js
15f13bb3c Update GLTFLoader.js
6d9c22a3b Update uniforms only when onWindowResize
881b25b58 Update ProjectionMatrix on change aspect
Material relacionado
Chuleta de Git
VER LA SOLUCIÓN
Aprende a usar Git con Bitbucket Cloud
Cada confirmación tiene un hash SHA-1 de identificación único. Estos ID se emplean para desplazarse por el cronograma confirmado y revisar las confirmaciones. De manera predeterminada, git log
solo muestra las confirmaciones de la rama seleccionada en ese momento. Es perfectamente posible que la confirmación que buscas se encuentre en otra rama. Para ver todas las confirmaciones de todas las ramas, puedes ejecutar git log --branches=*
. El comando git branch se utiliza para visualizar y visitar otras ramas. Al invocar el comando, git branch -a
devolverá una lista con los nombres de todas las ramas conocidas. Después, se puede registrar uno de los nombres de estas ramas mediante el comando git log
.
Si encuentras una referencia de confirmación al punto del historial que quieres visitar, puedes utilizar el comando git checkout
para visitar dicha confirmación. git checkout
es una forma sencilla de “cargar” cualquiera de estas instantáneas guardadas en tu máquina de desarrollo. Durante el curso normal del desarrollo, HEAD
apunta por lo general a la rama main
u otra rama local, pero, cuando extraes una confirmación anterior, HEAD
ya no apunta a una rama, sino que apunta directamente a una confirmación. Este estado recibe el nombre de "HEAD
desasociado" (detached HEAD) y se puede representar de la siguiente manera:
Extraer un archivo antiguo no mueve el puntero HEAD
. Este permanece en la misma rama y en la misma confirmación, evitando así un estado del tipo "HEAD desasociado". A continuación, puedes hacer una confirmación de la versión antigua de un archivo en una nueva instantánea como lo harías con cualquier otro cambio. Así que, en efecto, este uso del comando git checkout
en un archivo sirve para revertir a una versión antigua de un archivo individual. Para obtener más información sobre estos dos modos, visita la página acerca del comando git checkout.
Visualización de una versión antigua
En este ejemplo, se asume que has comenzado a desarrollar un disparatado experimento, pero no sabes con seguridad si quieres conservarlo o no. Para decidirte, quieres echar un vistazo al estado del proyecto antes de empezar el experimento. Primero, tendrás que encontrar el ID de la revisión que deseas ver.
git log --oneline
Pongamos que el historial del proyecto presenta un aspecto similar al siguiente:
b7119f2 Continue doing crazy things
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Puedes usar git checkout
para ver la confirmación “Make some import changes to hello.txt” de la siguiente manera:
git checkout a1e8fb5
De este modo, tu directorio de trabajo coincidirá con el estado exacto de la confirmación a1e8fb5
. Puedes consultar y editar archivos, compilar el proyecto y realizar pruebas sin preocuparte de perder el estado actual del proyecto. Nada de lo que hagas aquí se guardará en tu repositorio. Para continuar con el desarrollo, debes volver al estado “actual” del proyecto:
git checkout main
Se presupone que estás desarrollando sobre la rama main
predeterminada. Una vez que estás de vuelta en la rama main
, puedes usar tanto el comando git revert como git reset para deshacer cualquier cambio no deseado.
Deshacer una instantánea confirmada
Técnicamente, existen varias estrategias diferentes para "deshacer" un commit. Los siguientes ejemplos presuponen que tenemos un historial de commits como el siguiente:
git log --oneline
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
Nos centraremos en deshacer la confirmación 872fa7e Try something crazy
. Puede que la cosa se haya descontrolado un poco.
Deshacer una confirmación con git checkout
Al utilizar el comando git checkout
, podemos comprobar el commit anterior, a1e8fb5,
poniendo el repositorio en un estado antes de que tuviera lugar la locura. Comprobar un commit específico pondrá el repositorio en un estado "HEAD desasociado". Esto significa que ya no estás trabajando en ninguna rama. En un estado desasociado, cualquier nuevo commit que hagas quedará huérfano cuando vuelvas a cambiar las ramas a una rama establecida. Los commits huérfanos están listos para que el recolector de basura de Git los elimine. El recolector de basura se ejecuta en un intervalo configurado y destruye de forma permanente los commits huérfanos. Para evitar que se recojan como basura commits huérfanos, es preciso asegurarse de que se está en una rama.
A partir del estado HEAD desasociado, podemos ejecutar git checkout -b new_branch_without_crazy_commit
. De este modo, se creará una nueva rama llamada new_branch_without_crazy_commit
y se cambiará a ese estado. El repositorio estará ahora en un nuevo cronograma del historial en el que la confirmación 872fa7e
ya no existe. Llegados a este punto, podemos continuar trabajando en esta nueva rama en la que la confirmación 872fa7e
ya no existe y considerarla "desecha". Desafortunadamente, si necesitas la rama anterior (e igual era tu rama main
), esta estrategia para deshacer la acción no resulta adecuada. Veamos unas cuantas estrategias al respecto. Para ver más información y ejemplos, consulta nuestro análisis en profundidad sobre git checkout.
Deshacer una confirmación pública con git revert
Supongamos que hemos vuelto a nuestro ejemplo de historial de commits original. El historial que incluye el commit 872fa7e
. Esta vez vamos a probar a revertir una acción "deshacer". Si ejecutamos git revert HEAD
, Git creará un nuevo commit con lo contrario del último. Esto añade un nuevo commit al historial de ramas actual que ahora tiene esta apariencia:
git log --oneline
e2f9a78 Revert "Try something crazy"
872fa7e Try something crazy
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
En este momento, hemos “deshecho” técnicamente la confirmación 872fa7e
. Aunque 872fa7e
sigue existiendo en el historial, la nueva confirmación e2f9a78
es una reversión de los cambios de 872fa7e
. A diferencia de nuestra estrategia de checkout anterior, podemos seguir usando la misma rama. Esta solución es una anulación correcta. Es el método idóneo para deshacer una acción al trabajar con repositorios compartidos públicos. Si debes mantener un historial de Git mínimo y seleccionado, puede que esta estrategia no sea la adecuada.
Deshacer una confirmación con git reset
Con esta estrategia para deshacer acciones, continuaremos con nuestro ejemplo de trabajo. git reset es un comando ampliado con múltiples usos y funciones. Si invocamos git reset --hard a1e8fb5
, el historial de confirmaciones se restablece a esa confirmación especificada. Al examinar el historial de confirmaciones con git log
, ahora se ve lo siguiente:
git log --oneline
a1e8fb5 Make some important changes to hello.txt
435b61d Create hello.txt
9773e52 Initial import
El resultado del registro muestra que las confirmaciones e2f9a78
y 872fa7e
ya no se encuentran en el historial de confirmaciones. Llegados a este punto, podemos seguir trabajando y creando nuevas confirmaciones como si los cambios un tanto locos de las confirmaciones “crazy” nunca hubieran existido. Este método para deshacer cambios es el que más limpio deja el historial. Realizar un restablecimiento va muy bien para los cambios locales, pero complica más el trabajo con un repositorio remoto compartido. Si tenemos un repositorio remoto compartido con la confirmación 872fa7e
e intentamos ejecutar el comando git push
en una rama donde hemos restablecido el historial, Git lo detectará y devolverá un error. Git asumirá que la rama que intentamos enviar está desactualizada debido a que le faltan confirmaciones. En estos casos, el comando git revert
debería ser el método empleado para deshacer acciones.
Deshacer la última confirmación
En la sección anterior, hemos analizado distintas estrategias para deshacer las confirmaciones. Todas estas estrategias también son aplicables a la confirmación más reciente. Sin embargo, en algunos casos igual no hace falta eliminar o restablecer la última confirmación. Tal vez solo se hizo precipitadamente. En este caso, puedes modificar la confirmación más reciente. Una vez que hayas realizado más cambios en el directorio de trabajo y los hayas preparado para la confirmación mediante el comando git add, puedes ejecutar git commit --amend
. De esta forma, Git abrirá el editor de sistema configurado y te permitirá modificar el último mensaje de confirmación. Los nuevos cambios se añadirán a la confirmación corregida.
Deshacer cambios no confirmados
Los cambios residen en el índice del entorno de ensayo y el directorio de trabajo antes de que se confirmen en el historial del repositorio. Es posible que tengas que deshacer cambios dentro de estas dos áreas. El índice del entorno de ensayo y el directorio de trabajo son mecanismos internos de gestión del estado de Git. Si quieres información más detallada sobre el funcionamiento de estos dos mecanismos, visita la página sobre el comando git reset, donde se exploran a fondo.
El directorio de trabajo
El directorio de trabajo se sincroniza generalmente con el sistema de archivos local. Para deshacer cambios en el directorio de trabajo, puedes editar los archivos como de costumbre utilizando tu editor favorito. Git dispone de un par de utilidades que ayudan a gestionar el directorio de trabajo. Por un lado, está el comando git clean, una práctica utilidad para deshacer cambios en el directorio de trabajo. Por otro lado, el comando git reset
puede invocarse con las opciones --mixed
o --hard
y restablecerá el directorio de trabajo.
Índice del entorno de ensayo
El comando git add sirve para añadir cambios en el índice del entorno de ensayo. git reset
se utiliza sobre todo para deshacer los cambios del índice del entorno de ensayo. Un comando reset con la opción --mixed
devolverá todos los cambios pendientes del índice del entorno de ensayo al directorio de trabajo.
Deshacer cambios públicos
Cuando se trabaja en un equipo con repositorios remotos, se debe prestar especial atención a la hora de deshacer cambios. Por lo general, debería considerarse que git reset
es un método local para deshacer acciones. El comando reset debería emplearse para deshacer cambios en una rama privada. De este modo, se aísla de forma segura la eliminación de las confirmaciones de otras ramas que otros desarrolladores puedan estar usando. Los problemas surgen cuando se ejecuta un reset en una rama compartida y luego esta se envía de manera remota mediante git push
. En este escenario, Git impedirá el envío y objetará que la rama que se pretende enviar está desactualizada con respecto a la rama remota, ya que faltan confirmaciones.
El método preferido para deshacer un historial compartido es git revert
. Un revert es más seguro que un reset porque no eliminará ningún commit de un historial compartido. Un revert conservará los commits que quiera deshacer y creará un nuevo commit que invierta el commit no deseado. Este método es más seguro para la colaboración remota compartida, porque un desarrollador remoto puede entonces "pedir" la rama y recibir el nuevo commit revertido que deshace el commit no deseado.
Resumen
Hemos analizado muchas estrategias generales para deshacer acciones en Git.‑ Es importante recordar que hay más de una forma de deshacer acciones en un proyecto de Git. En la mayor parte de esta página se han tocado temas más profundos que se explican con más detalle en las páginas específicas de los comandos de Git correspondientes. Las herramientas más utilizadas para deshacer acciones son git checkout, git revert y git reset. Estos son algunos puntos clave que debes recordar:
- Una vez que se ha hecho un commit de los cambios, estos suelen volverse permanentes.
- Utiliza
git checkout
para desplazarte y revisar el historial de commits. git revert
es la mejor herramienta para deshacer cambios públicos compartidos.git reset
es más adecuado para deshacer cambios privados locales.
Además de los principales comandos de deshacer, hemos visto otras utilidades de Git: git log para encontrar confirmaciones perdidas; git clean para deshacer cambios a los que no se le ha hecho una confirmación; o git add para modificar el índice de preparación.
Cada uno de estos comandos tiene su propia documentación detallada. Para informarte más sobre un comando concreto de los que hemos mencionado aquí, visita los enlaces correspondientes.
Compartir este artículo
Tema siguiente
Lecturas recomendadas
Consulta estos recursos para conocer los tipos de equipos de DevOps o para estar al tanto de las novedades sobre DevOps en Atlassian.