Git, de forma fácil: cambia el historial con rebase—parte II
Or Kamara
17 de junio de 2020
0 minutos de lecturaTe damos la bienvenida a la segunda parte sobre cómo trabajar con Git de forma fácil.
En el artículo anterior, repasamos los conceptos básicos de Rebase y dos situaciones comunes que podríamos encontrar al trabajar con Git. Puedes encontrar la primera parte aquí. En esta parte, repasaremos cuatro situaciones comunes más y algunas conclusiones.
¡Empecemos!
Situaciones comunes (¡y cómo resolverlas!)—parte II
Retomemos donde nos quedamos la última vez con algunas situaciones comunes en las que quizás quieras cambiar el historial de tu código, y cómo hacerlo con Git:
1. Dividir un commit antiguo en dos (edit)
Supongamos que acabas de darte cuenta de que cometiste un error al combinar 2 commits (consulta la parte I para obtener más detalles) y quieres deshacer el squash de 17a73c1 en e2952e7, para que el nuevo archivo quede en un commit diferente. La solución sería ejecutar todos los commits hasta el punto específico que necesitas editar, detenerte, hacer los cambios y continuar. En otras palabras, usa la opción edit .
Empezaremos ejecutando git rebase -i master de nuevo, pero esta vez con la opción edit en el commit que queremos dividir (el segundo commit, `6871683`):
Al salir de la pantalla de rebase, veremos lo siguiente:
Básicamente, Git ejecutó el primer y el segundo commit, se detuvo y ahora nosotros tenemos el control. ¡Podemos hacer todos los cambios que queramos!
Este es el estado actual de nuestro gráfico de Git:
Como mencionamos antes, básicamente queremos dividir el segundo commit en 2 commits distintos, uno por archivo. El primer paso sería restablecer los cambios del segundo commit ejecutando git reset --soft HEAD^. El comando reset cambia el commit al que apunta actualmente la rama HEAD. Al usar la opción --soft, podemos conservar el índice y el directorio de trabajo, mientras que todos los archivos modificados entre el HEAD original y el commit quedan en el área de preparación.
Este es el nuevo estado de Git. Como puedes ver, ambos archivos están guardados en el área de preparación:
Ahora quitemos b2.txt de la lista de archivos preparados ejecutando git restore --staged b2.txt:
Con solo b.txt como archivo preparado, ahora podemos confirmar la primera parte del segundo commit. Luego preparamos b2.txt y confirmamos la segunda parte del segundo commit:
Ahora nuestro gráfico de Git se ve así:
El último paso sería continuar el rebase y ejecutar el resto de los commits con:
git rebase --continue. El gráfico final de Git debería verse así:
2. Modificar todos los archivos de un commit específico (edit)
Probablemente ya conoces la siguiente situación: enviaste todo tu código, perfectamente dividido en varios commits, pero luego te das cuenta de que olvidaste ejecutar el linter. Como explicamos antes, la solución no debería ser crear otro commit llamado fix linting, sino corregir el linting en todos y cada uno de los commits.
Si el cambio es menor, podemos usar la opción squash, pero si hay varios cambios en varios commits, lo mejor será ejecutar nuestro script de linting uno por uno en cada commit (o en los commits específicos que queramos corregir). Para eso, podemos volver a usar la opción edit (como en el ejemplo anterior).
Ejecutemos de nuevo git commit rebase -i y usemos la opción edit en el primer commit (un commit con varios archivos):
Como antes, Git se detiene después de ejecutar el primer commit:
Ahora podemos ejecutar nuestro linter (por ejemplo, npm run lint) y revisar el estado de nuestro repositorio:
Como puedes ver, el script del linter modificó el contenido de 6 archivos (a*.txt). Ahora solo tenemos que enmendar el commit actual (preparando y confirmando los cambios) y continuar con el rebase:
Y el gráfico de Git debería quedar así:
3. Asegurarte de que las pruebas pasen en cada commit (exec)
Al dividir tu código en varios commits, recuerda que cada commit debe funcionar por sí solo. En otras palabras, después de combinar varios commits en una de las ramas principales, deberías poder volver a cada uno de ellos y esperar que el código compile y que todas las pruebas pasen.
Entonces, ¿cómo puedes validar eso antes de combinar los commits?
¡Ejecutemos manualmente todas las pruebas en cada commit! Es broma, por supuesto: deberíamos hacerlo automáticamente :) Para eso, podemos usar la opción exec .
Esta opción nos ayuda a ejecutar scripts de shell como parte del proceso de rebase. Para hacerlo, solo tenemos que agregar líneas nuevas con el comando exec donde queramos. Por ejemplo, ejecutemos de nuevo git rebase -i master:
Ahora viene la parte divertida: ejecutar las pruebas (con el script ./run_tests.sh) después de cada commit:
Este es el resultado al salir de la ventana de rebase:
Como puedes ver, Git ejecutó el script de pruebas después de cada commit. Así que ahora sabemos que algo en el commit feat: 2nd commit hace que fallen las pruebas. También es posible agregar un único comando exec después de cada commit ejecutando:
$ git rebase -i --exec "./run_tests.sh"
Lo último (en realidad, lo primero) que debes saber: cómo cancelar
Esto no es una situación, sino más bien una advertencia: ¡el comando rebase puede ser peligroso! Usarlo sin comprender los efectos de los comandos podría arruinar tu trabajo. Por eso, empezaré con 2 recomendaciones:
Antes de empezar a modificar los commits, asegúrate siempre de tener una copia de seguridad adecuada de tu repositorio de Git. Lo más sencillo que me gusta hacer es enviar todos mis cambios a una rama remota. Si algo sale mal, siempre puedo volver al código original (con
git reset).Asegúrate de entender los comandos. En lugar de usarlos por primera vez en tu código real, pruébalos antes en un repositorio temporal de Git.
Ten en cuenta que siempre puedes detener el proceso de rebase y volver al estado original:
En la pantalla inicial de rebase, solo elimina todas las líneas de commits y no cambiará nada.
A mitad del proceso de rebase, si por alguna razón te pierdes y no sabes qué hacer, siempre puedes ejecutar
git rebase --abort. Este comando detiene el proceso de rebase y devuelve el repositorio a su estado original (antes de ejecutargit rebase -i).
En resumen
Como vimos en los últimos ejemplos, git rebase es un comando potente, sobre todo cuando se usa de forma interactiva. Hay una infinidad de casos en los que podemos usarlo, pero espero haber logrado darte una idea básica de cuándo resulta útil cada opción.
Lo principal que me gustaría que te lleves de este artículo es que uses git rebase con criterio y sin miedo. Sé que al principio puede dar un poco de temor y que quizás quieras que alguien te acompañe mientras presionas la tecla Enter, pero no pasa nada. Si sigues practicando, se volverá parte de tu rutina. Además, estoy seguro de que hay muchas más situaciones, adaptadas a tus casos de uso específicos, en las que este comando resulta útil.
¡Que lo disfrutes!
Comienza con Capture the Flag
Aprende a resolver desafíos de Capture the Flag con nuestro taller virtual 101 a pedido.



