Una guía para deshacer errores con Git (Parte 1)

No importa la experiencia que tengas, los errores son una parte inevitable del desarrollo de software. ¡Pero podemos aprender a repararlos! Y esto es lo que veremos en esta serie de dos partes: cómo deshacer errores usando Git.
Trabajar con código es una tarea arriesgada: ¡hay innumerables maneras de dispararse en el pie! Pero si usas Git como sistema de control de versiones, entonces tienes una excelente red de seguridad. Muchas herramientas de "deshacer" le ayudarán a recuperarse de casi cualquier tipo de desastre.
En este primer artículo de nuestra serie de dos partes, veremos varios errores y cómo deshacerlos de forma segura con Git.
Descartar cambios no confirmados en un archivo
Supongamos que ha realizado algunos cambios en un archivo y, después de un tiempo, nota que sus esfuerzos no conducen a ninguna parte. Lo mejor sería empezar de nuevo y deshacer los cambios realizados en este archivo.
La buena noticia es que si no has realizado las modificaciones, deshacerlas es bastante fácil. Pero también hay algunas malas noticias: ¡ no puedes recuperar las modificaciones una vez que las has deshecho! Debido a que no se han guardado en la “base de datos” de Git, ¡no hay forma de restaurarlos!
Dejando de lado esta pequeña advertencia, deshagamos nuestros cambios en index.html:
$ git restore index.html
Este comando restaurará nuestro archivo a su último estado confirmado, limpiándolo de cualquier cambio local.
Restaurar un archivo eliminado
Llevemos el ejemplo anterior un paso más allá. Digamos que, en lugar de modificarlo , loindex.html has eliminado por completo . Nuevamente, supongamos que aún no ha enviado esto al repositorio.
Le complacerá saber que git restoreestá equipado para manejar esta situación con la misma facilidad:
$ git restore index.html
Al restorecomando realmente no le importa qué le hiciste exactamente a ese pobre archivo. ¡Simplemente recrea su último estado comprometido!
Descarta algunos de tus cambios
La mayoría de los días son una mezcla de buen y mal trabajo. Y a veces tenemos ambas cosas en un solo archivo: algunas de tus modificaciones serán geniales (seamos generosos y llamémoslas geniales), mientras que otras se pueden tirar a la basura.
Git te permite trabajar con cambios de forma muy granular. Usar git restorecon la -pbandera hace que todo este asunto de deshacer sea mucho más matizado:
$ git restore -p index.html
Git nos toma de la mano y nos guía a través de cada uno de los cambios en el archivo, preguntándonos si queremos desecharlo (en cuyo caso, escribiríamos y) o conservarlo (escribiendo n):
, en la que este servidor está trabajando.
Usar la --amendopción le permite cambiar este último compromiso (y solo este):
$ git commit --amend -m "A message without typos"
En caso de que también hayas olvidado agregar algún cambio determinado , puedes hacerlo fácilmente. Simplemente prepárelo como cualquier otro cambio con el git addcomando y luego ejecútelo git commit --amendnuevamente:
$ git add forgotten-change.txt$ git commit --amend --no-edit
La --no-editopción le dice a Git que esta vez no queremos cambiar el mensaje de confirmación.
Revertir los efectos de una mala confirmación
En todos los casos anteriores, reconocimos rápidamente nuestros errores. Pero a menudo sólo nos enteramos de un error mucho después de haberlo cometido. El mal compromiso se encuentra en nuestro historial de revisiones, mirándonos con sarcasmo.
Por supuesto, también hay una solución para este problema: ¡el git revertcomando! Y resuelve nuestro problema de una manera muy no destructiva. En lugar de eliminar nuestro compromiso incorrecto del historial, crea un nuevo compromiso que contiene los cambios opuestos.
Realizar eso en la línea de comando es tan simple como proporcionar el hash de revisión de esa confirmación incorrecta al git revertcomando:
$ git revert 2b504bee
Como se mencionó, esto no eliminará nuestra confirmación incorrecta (lo que podría ser problemático si ya la hemos compartido con colegas en un repositorio remoto). En su lugar, se creará automáticamente una nueva confirmación que contiene los cambios revertidos.
Restaurar un estado anterior del proyecto
A veces tenemos que admitir que nos hemos codificado en un callejón sin salida. Quizás nuestros últimos compromisos no hayan dado frutos y sea mejor deshacerlos.
Afortunadamente, este problema es bastante fácil de resolver. Simplemente necesitamos proporcionar el hash SHA-1 de la revisión a la que queremos volver cuando usemos el git resetcomando. Cualquier confirmación que venga después de esta revisión desaparecerá:
$ git reset --hard 2b504bee
La --hardopción asegura que nos quedemos con una copia de trabajo limpia . Alternativamente, podemos usar la --mixedopción para un poco más de flexibilidad (y seguridad): --mixedpreservará los cambios contenidos en las confirmaciones eliminadas como cambios locales en nuestra copia de trabajo.
Lo primero que debes saber sobre reflog es que está ordenado cronológicamente . Por lo tanto, no debería sorprendernos ver nuestro reciente git reseterror en lo más alto. Si ahora queremos deshacer esto, simplemente podemos regresar al estado anterior, que también está protocoloizado aquí, ¡justo debajo!
Ahora podemos copiar el hash de confirmación de este estado seguro y crear una nueva rama basada en él:
$ git branch happy-ending e5b19e4
Of course, we could have also used git reset e5b19e4 to return to this state. Personally, however, I prefer to create a new branch: It comes with no downsides and allows me to inspect whether this state is really what I want.
Restore a Single File From a Previous State
Until now, when we’ve worked with committed states, we’ve always worked with the complete project. But what if we want to restore a single file, not the whole project? For example, let’s say we’ve deleted a file, only to find out much later that we shouldn’t have. To get us out of this misery, we’ll have to solve two problems:
- find the commit where we deleted the file,
- then (and only then) restore it.
Let’s go search the commit history for our poor lost file:
$ git log -- filename
The output of this lists all commits where this file has been modified. And because log output is sorted chronologically, we shouldn’t have to search for long — the commit in which we deleted the file will likely be topmost (because after deleting it, the file probably wouldn’t show up in newer commits anymore).
With that commit’s hash and the name of our file, we have everything we need to bring it back from the dead:
$ git checkout deletion commit hash~1 -- filename
Note that we’re using ~1 to address the commit before the one where we made the deletion. This is necessary because the commit where the deletion happened doesn’t contain the file anymore, so we can’t use it to restore the file.
You Are Now (Almost) Invincible
During the course of this article, we’ve witnessed many disasters — but we’ve seen that virtually nothing is beyond repair in Git! Once you know the right commands, you can always find a way to save your neck.
But to really become invincible (in Git, that is), you’ll have to wait for the second part of this series. We will look at some more hairy problems, such as how to recover deleted branches, how to move commits between branches, and how to combine multiple commits into one!
In the meantime, if you want to learn more about undoing mistakes with Git, I recommend the free “First Aid Kit for Git”, a series of short videos about this very topic.
See you soon in part two of this series! Subscribe to the Smashing Newsletter to not miss that one. 😉
(vf, il, al)Explore more on
- Git
- JavaScript
- Tools

Deja un comentario