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

Publicado: 2022-03-10
Resumen rápido ↬ Errores. Estos crueles villanos ni siquiera se detienen en el hermoso mundo del desarrollo de software. Pero aunque no podemos evitar cometer errores, ¡podemos aprender a deshacerlos! Este artículo te mostrará las herramientas adecuadas para tu trabajo diario con Git. Es posible que también desee consultar el primer artículo de la serie.

En esta segunda parte de nuestra serie sobre "Deshacer errores con Git", volveremos a mirar valientemente el peligro a los ojos: he preparado cuatro nuevos escenarios apocalípticos, que incluyen, por supuesto, algunas formas inteligentes de salvarnos el cuello. Pero antes de sumergirnos: ¡eche un vistazo a los artículos anteriores sobre Git para obtener aún más métodos de autorrescate que lo ayuden a deshacer sus errores con Git!

¡Vamos!

Recuperación de una sucursal eliminada mediante Reflog

¿Alguna vez eliminó una rama y, poco después, se dio cuenta de que no debería haberlo hecho? En el improbable caso de que no conozcas este sentimiento, puedo decirte que no es bueno. Te invade una mezcla de tristeza e ira, mientras piensas en todo el arduo trabajo que se dedicó a las confirmaciones de esa rama, todo el código valioso que ahora has perdido.

Afortunadamente, hay una manera de revivir esa rama de entre los muertos, con la ayuda de una herramienta de Git llamada "Reflog". Habíamos usado esta herramienta en la primera parte de nuestra serie, pero aquí hay un pequeño repaso: Reflog es como un diario donde Git anota cada movimiento del puntero HEAD en su repositorio local. En otras palabras menos nerds: cada vez que pagas, confirmas, fusionas, cambias de base, seleccionas, etc., se crea una entrada de diario. ¡Esto hace que Reflog sea una red de seguridad perfecta cuando las cosas van mal!

Veamos un ejemplo concreto:

 $ git branch * feature/login master

Podemos ver que actualmente tenemos verificada nuestra feature/login de sesión de sucursal. Digamos que esta es la rama que vamos a eliminar (sin darnos cuenta). Sin embargo, antes de que podamos hacer eso, debemos cambiar a una rama diferente porque no podemos eliminar nuestra rama HEAD actual.

 $ git checkout master $ git branch -d feature/login

Nuestra valiosa rama de características ya no está, y les daré un minuto para (a) comprender la gravedad de nuestro error y (b) llorar un poco. ¡Después de que hayas limpiado las lágrimas, tenemos que encontrar una manera de traer de vuelta esta rama! Abramos Reflog (simplemente escribiendo git reflog ) y veamos qué nos depara:

Reflog de Git protocoliza todas las acciones principales en nuestro repositorio local
Reflog de Git protocoliza todas las acciones principales en nuestro repositorio local. (Vista previa grande)

Aquí hay algunos comentarios para ayudarlo a dar sentido a la salida:

  • En primer lugar, debe saber que Reflog ordena sus entradas cronológicamente: los elementos más nuevos están en la parte superior de la lista.
  • El elemento superior (y, por lo tanto, el más nuevo) es el comando git checkout que realizamos antes de eliminar la rama. Está registrado aquí en el Reflog porque es uno de estos "movimientos de puntero HEAD" que el Reflog registra tan debidamente.
  • Para deshacer nuestro grave error, simplemente podemos volver al estado anterior , que también se registra limpia y claramente en el Reflog.

Así que intentemos esto, creando una nueva rama (con el nombre de nuestra rama "perdida") que comienza en este hash SHA-1 de estado "antes":

 $ git branch feature/login 776f8ca

¡Y voilá! ¡Te encantará ver que ahora hemos restaurado nuestra sucursal aparentemente perdida!

Si está utilizando una GUI de escritorio Git como "Torre", puede tomar un buen atajo: simplemente presione CMD + Z en su teclado para deshacer el último comando, ¡incluso si acaba de eliminar violentamente una rama!

Una GUI de escritorio como Tower puede facilitar el proceso de deshacer errores.
¡Más después del salto! Continúe leyendo a continuación ↓

Mover una confirmación a una rama diferente

En muchos equipos, existe un acuerdo para no realizar compromisos en ramas de ejecución prolongada como main o develop : ramas como estas solo deben recibir nuevos compromisos a través de integraciones (por ejemplo, fusiones o rebases). Y, sin embargo, por supuesto, los errores son inevitables: ¡a veces olvidamos y cometemos en estas ramas, no obstante! Entonces, ¿cómo podemos limpiar el desastre que hicimos?

Mover una confirmación a su rama de destino correcta
Nuestro compromiso aterrizó en la rama equivocada. ¿Cómo podemos moverlo a su sucursal de destino correcta? (Vista previa grande)

Afortunadamente, este tipo de problemas se pueden corregir fácilmente. Arremanguémonos y manos a la obra.

El primer paso es cambiar a la rama de destino correcta y luego mover la confirmación usando el comando cherry-pick :

 $ git checkout feature/login $ git cherry-pick 776f8caf

Ahora tendrá la confirmación en la rama deseada, donde debería haber estado en primer lugar. ¡Increíble!

Pero todavía queda una cosa por hacer: ¡necesitamos limpiar la rama donde aterrizó accidentalmente al principio! El comando cherry-pick , por así decirlo, creó una copia de la confirmación, pero el original aún está presente en nuestra rama de ejecución prolongada:

Una copia de la confirmación en la rama correcta, pero aún se muestra que el original está en la rama incorrecta
Creamos con éxito una copia de la confirmación en la rama correcta, pero el original todavía está aquí, en la rama incorrecta. (Vista previa grande)

Esto significa que tenemos que volver a nuestra rama de ejecución prolongada y usar git reset para eliminarla:

 $ git checkout main $ git reset --hard HEAD~1

Como puede ver, estamos usando el comando git reset aquí para borrar la confirmación defectuosa. El parámetro HEAD~1 le dice a Git que "retroceda 1 revisión detrás de HEAD", borrando efectivamente la confirmación superior (y en nuestro caso: no deseada) del historial de esa rama.

Y listo: la confirmación ahora está donde debería haber estado en primer lugar y nuestra rama de ejecución prolongada está limpia, ¡como si nuestro error nunca hubiera ocurrido!

Edición del mensaje de una confirmación antigua

Es demasiado fácil pasar de contrabando un error tipográfico en un mensaje de confirmación, y solo descubrirlo mucho más tarde. En tal caso, la buena y antigua opción --amend de git commit no se puede usar para solucionar este problema, porque solo funciona para la última confirmación. Para corregir cualquier confirmación que sea más antigua, tenemos que recurrir a una herramienta de Git llamada “Interactive Rebase”.

Un mensaje de confirmación que vale la pena cambiar
Aquí hay un mensaje de compromiso que vale la pena cambiar. (Vista previa grande)

Primero, tenemos que decirle a Interactive Rebase qué parte del historial de confirmaciones queremos editar. Esto se hace alimentándolo con un hash de confirmación: la confirmación principal de la que queremos manipular.

 $ git rebase -i 6bcf266b

A continuación, se abrirá una ventana de edición. Contiene una lista de todas las confirmaciones después de la que proporcionamos como base para la Rebase interactiva en el comando:

Mostrando el rango de confirmaciones que seleccionamos para editar en nuestra sesión de Rebase interactiva
El rango de confirmaciones que seleccionamos para editar en nuestra sesión de Rebase interactiva. (Vista previa grande)

Aquí, es importante que no sigas tu primer impulso: en este paso, todavía no editamos el mensaje de confirmación. En su lugar, solo le decimos a Git qué tipo de manipulación queremos hacer con qué compromiso(s). Muy convenientemente, hay una lista de palabras clave de acción anotadas en los comentarios en la parte inferior de esta ventana. Para nuestro caso, marcamos la línea n.º 1 con una reword (reemplazando así la pick estándar).

Todo lo que queda por hacer en este paso es guardar y cerrar la ventana del editor. A cambio, se abrirá una nueva ventana del editor que contiene el mensaje actual de la confirmación que marcamos. ¡Y finalmente es el momento de hacer nuestras ediciones!

Aquí está todo el proceso de un vistazo para usted:

Uso de Interactive Rebase para editar un mensaje de confirmación anterior, de principio a fin.

Corrección de un compromiso roto (de una manera muy elegante)

Finalmente, vamos a echar un vistazo a fixup , la navaja suiza de las herramientas de deshacer. En pocas palabras, le permite corregir una confirmación rota/incompleta/incorrecta después del hecho. Es realmente una herramienta maravillosa por dos razones:

  1. No importa cuál sea el problema.
    Es posible que haya olvidado agregar un archivo, debería haber eliminado algo, realizado un cambio incorrecto o simplemente un error tipográfico. fixup funciona en todas estas situaciones!
  2. Es extremadamente elegante.
    Nuestra reacción normal e instintiva a un error en una confirmación es producir una nueva confirmación que solucione el problema. Esta forma de trabajar, por muy intuitiva que parezca, hace que tu historial de confirmaciones parezca muy caótico, muy pronto. Tiene confirmaciones "originales" y luego estas pequeñas confirmaciones "curitas" que arreglan las cosas que salieron mal en las confirmaciones originales. Su historial está plagado de pequeñas confirmaciones de curitas sin sentido que dificultan la comprensión de lo que sucedió en su base de código.
Su historial de confirmaciones puede ser muy difícil de leer si corrige constantemente pequeños errores con las llamadas confirmaciones de curitas.
La corrección constante de pequeños errores con "compromisos de curita" hace que su historial de compromisos sea muy difícil de leer. (Vista previa grande)

Aquí es donde entra en fixup la reparación. Le permite aún hacer este compromiso de curita de corrección. Pero aquí viene la magia: luego lo aplica al compromiso original roto (reparándolo de esa manera) y luego descarta por completo el feo compromiso de curita.

Fixup aplica sus correcciones al compromiso original y luego elimina el compromiso de curita superfluo
Fixup aplica sus correcciones a la confirmación original y luego elimina la confirmación de curita superflua. (Vista previa grande)

¡Podemos pasar juntos por un ejemplo práctico! Digamos que la confirmación seleccionada aquí está rota.

Arreglando el compromiso incorrecto seleccionado de una manera elegante
El compromiso seleccionado es incorrecto, y lo arreglaremos de una manera elegante. (Vista previa grande)

Digamos también que he preparado cambios en un archivo llamado error.html que solucionará el problema. Aquí está el primer paso que debemos hacer:

 $ git add error.html $ git commit --fixup 2b504bee

Estamos creando una nueva confirmación, pero le decimos a Git que es especial: es una solución para una confirmación anterior con el hash SHA-1 especificado ( 2b504bee en este caso).

El segundo paso, ahora, es iniciar una sesión de Interactive fixup , porque la corrección pertenece al gran conjunto de herramientas de Interactive Rebase.

 $ git rebase -i --autosquash 0023cddd

Vale la pena explicar dos cosas acerca de este comando. Primero, ¿por qué proporcioné 0023cddd como hash de revisión aquí? Porque necesitamos comenzar nuestra sesión de Rebase interactiva en la confirmación principal de nuestro compañero roto.

Segundo, ¿para qué sirve la opción --autosquash ? ¡Nos quita mucho trabajo de encima! En la ventana del editor que ahora se abre, ya está todo preparado para nosotros:

La ventana de sesión de Rebase interactivo
La ventana de sesión de Interactive Rebase (vista previa grande)

Gracias a la opción --autosquash , Git ya ha hecho el trabajo pesado por nosotros:

  1. Marcó nuestro pequeño compromiso de curita con la palabra clave de acción de fixup . De esa manera, Git lo combinará con el compromiso directamente arriba y luego lo descartará.
  2. También reordenó las líneas en consecuencia, moviendo nuestro compromiso de curita directamente debajo del compromiso que queremos corregir (nuevamente: ¡la fixup funciona al combinar el compromiso marcado con el de arriba !).

En resumen: ¡no hay nada que hacer por nosotros más que cerrar la ventana!

Echemos un vistazo final al resultado final.

  • La confirmación anteriormente rota está arreglada: ahora contiene los cambios que preparamos en nuestra confirmación curita.
  • El feo compromiso de curita en sí mismo ha sido descartado: el historial de compromisos es limpio y fácil de leer, como si no hubiera ocurrido ningún error.
Un ejemplo de cómo se ve un historial de confirmación limpio
El resultado final después de usar la herramienta de corrección: ¡un historial de confirmaciones limpio! (Vista previa grande)

Saber deshacer errores es un superpoder

¡Felicidades! ¡Ahora puedes salvar tu cuello en muchas situaciones difíciles! Realmente no podemos evitar estas situaciones: no importa la experiencia que tengamos como desarrolladores, los errores son simplemente parte del trabajo. Pero ahora que sabes cómo lidiar con ellos, puedes enfrentarlos con un ritmo cardíaco relajado.

Si desea obtener más información sobre cómo deshacer errores con Git, puedo recomendar el "Botiquín de primeros auxilios para Git" gratuito, una serie de videos cortos sobre exactamente este tema.

Diviértete cometiendo errores y, por supuesto, deshaciéndolos con facilidad.