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 aspectCada 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 <branch_name>.
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 --onelinePongamos 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 importPuedes usar git checkout para ver la confirmación āMake some import changes to hello.txtā de la siguiente manera:
git checkout a1e8fb5De 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 mainSe 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 importNos 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 importEn 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 importEl 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 checkoutpara desplazarte y revisar el historial de commits.git revertes la mejor herramienta para deshacer cambios públicos compartidos.git resetes 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.