El control de versiones con Git se ha convertido en un estándar en el arsenal de herramientas de cualquier desarrollador moderno. Comandos como commit
, push
y pull
se han convertido en una segunda naturaleza. Sin embargo, relativamente pocos desarrolladores conocen las características “más avanzadas” de Git y cuán valiosas pueden ser! En este artículo, exploraremos el “rebase interactivo”, una de las herramientas más poderosas de Git.
Por qué el Rebase Interactivo Debe Ser Parte del Conjunto de Herramientas de Todo Desarrollador
En pocas palabras, y sin exagerar, el rebase interactivo puede ayudarte a ser un mejor desarrollador, permitiéndote crear un historial de confirmaciones limpio y bien estructurado en tus proyectos.
¿Por qué es importante un historial de confirmaciones bien estructurado? Imagina lo contrario: un historial de confirmaciones difícil de leer, en el que no tienes idea de lo que tus colegas realmente hicieron con sus cambios recientes. Cada vez más “esquinas oscuras” comienzan a aparecer en un proyecto así, y solo entiendes las pequeñas partes en las que trabajaste tú mismo.
Contrasta esto con un historial de confirmaciones limpio y bien estructurado: ayuda a hacer que la base de código de un proyecto sea más legible y más fácil de entender. ¡Esta es una pieza esencial para un proyecto saludable y duradero!
Lo que el Rebase Interactivo Puede Hacer por Ti
El Rebase Interactivo te ayuda a optimizar y limpiar tu historial de confirmaciones. Cubre muchos casos de uso diferentes, algunos de los cuales te permiten hacer lo siguiente:
- editar un mensaje de confirmación antiguo
- eliminar una confirmación
- aplanar/combinar múltiples confirmaciones
- reordenar confirmaciones
- arreglar commits antiguos
- dividir/reabrir commits antiguos para editar
Cuándo Usar Rebase Interactivo (y Cuándo No!)
Al igual que un par de otras herramientas de Git, el rebase interactivo “reescribe la historia”. Esto significa que, cuando manipulas una serie de commits utilizando rebase interactivo, esta parte de tu historia de commits será reescrita: los hashes SHA-1 de los commits habrán cambiado. Son, por así decirlo, objetos de commit completamente nuevos.
Este hecho implica una sencilla pero importante regla a seguir: no uses rebase interactivo (o otras herramientas que reescriban la historia) en commits que ya has compartido con tus colegas en un repositorio remoto. En su lugar, úsalo para limpiar tus propios commits locales, como en una de tus propias ramas de características, antes de fusionarlos en una rama de equipo.
El Mecanismo Básico de una Operación de Rebase Interactivo
Aunque hay muchas cosas diferentes que se pueden hacer con el rebase interactivo, el flujo de trabajo básico es siempre el mismo. Una vez que hayas entendido firmemente este mecanismo básico, el rebase interactivo perderá su aura de “misterio complejo” y se convertirá en un elemento valioso y accesible en tu cinturón de herramientas.
Paso 1: ¿Dónde deberías iniciar la sesión?
La primera pregunta que debes responder es: “¿Qué parte de mi historia de commits quiero manipular?” Esto te indica dónde deberías iniciar tu sesión de rebase interactivo. Vamos a hacer un ejemplo práctico y decir que nos gustaría editar un mensaje de commit antiguo (que es lo que realmente haremos en la práctica en un momento).
Nuestra situación inicial se muestra a continuación, donde estamos editando un mensaje de confirmación antiguo mediante rebase interactivo.
Para poder cambiar el mensaje de confirmación en C2
, debemos iniciar nuestra sesión de rebase interactivo en su confirmación padre (o incluso antes, si lo deseas). En este caso de ejemplo, usaríamos C1
como punto de partida para nuestra sesión de rebase interactivo.
Paso 2: iniciando la sesión real!
Iniciar la sesión real es bastante sencillo:
$ git rebase -i HEAD~3
Estamos utilizando el comando git rebase
con la bandera -i
(para indicar que queremos que sea “interactivo”) y proporcionamos la confirmación base (que determinamos en nuestro primer paso anterior). En este ejemplo, he utilizado HEAD~3
para especificar la confirmación que está “3 detrás de la confirmación HEAD”. Alternativamente, también podría haber proporcionado un hash SHA-1 específico.
Paso 3: indicando a Git lo que deseas hacer
Después de iniciar la sesión de rebase interactivo, se te presentará una ventana de editor donde Git lista una serie de confirmaciones, desde la más reciente hasta (pero sin incluir) la que elegiste como confirmación base en el Paso 1.
Hay dos cosas importantes a tener en cuenta en este paso:
- ¡Las confirmaciones se enumeran en orden inverso! La confirmación más nueva, que esperaríamos que aparezca en la parte superior, aparecerá en la parte inferior de la lista. No te preocupes: tu repositorio Git está en forma perfecta! 🥳 Recuerda que estamos en el proceso de realizar una operación de rebase interactivo, y esto requiere que Git reaplicar las confirmaciones de más antiguas a más recientes al final de la operación.
- ¡No realices tus cambios reales en esta ventana de edición! Aunque podrías estar ansioso por simplemente seguir adelante y cambiar el mensaje de confirmación en esta ventana de edición (después de todo, eso es lo que realmente queremos hacer…), debes mostrar algo de paciencia. Aquí, solo vamos a decirle a Git qué queremos hacer, pero no haremos el cambio real. ¡Pronto demostraré este punto en la práctica!
Con esta visión teórica fuera del camino, ¡vamos a sumergirnos en algunos casos prácticos juntos!
Editar un Mensaje de Confirmación Antiguo
Uno de los casos de uso muy populares de rebase interactivo es que puedes editar un mensaje de confirmación antiguo después del hecho. Podrías estar consciente de que git commit --amend
también te permite cambiar el mensaje de una confirmación, pero solo si es la última confirmación. Para cualquier confirmación más antigua que esa, tenemos que usar el rebase interactivo!
Echemos un vistazo a un escenario concreto. A continuación se muestra una imagen de un mal mensaje de confirmación que necesita ser corregido.
Nota: Para una mejor visión general y una visualización más clara, estoy usando el cliente de escritorio Tower Git en algunas de mis capturas de pantalla. No necesitas Tower para seguir este tutorial.
Para nuestro ejemplo, digamos que nos gustaría editar el mensaje de la confirmación actualmente titulado “Optimizar la estructura del marcado en el índice…”
Nuestro primer paso es determinar el commit base para comenzar esta sesión de rebase interactivo. Como debemos (al menos) retroceder hasta el padre de nuestro “mal compromiso”, comenzamos nuestra sesión en HEAD~3 (tres compromisos detrás del compromiso HEAD, que es el que tiene el título “Cambiar encabezados…”):
$ git rebase -i HEAD~3
Inmediatamente después de ejecutar este comando, se abrirá su editor favorito y presentará la lista de compromisos que acaba de seleccionar (al proporcionar un compromiso base).
Como recordatorio: aunque podría tentarlo hacerlo, no cambiamos el mensaje del compromiso aquí. Solo marcamos la línea respectiva con una “palabra clave de acción”. En nuestro caso, queremos reword
el compromiso (lo que significa que nos gustaría cambiar el mensaje del compromiso, pero dejar el resto del compromiso tal cual).
Prácticamente, todas las palabras clave de acción disponibles están documentadas en la parte inferior de esta ventana, ¡así que no es necesario recordar nada de memoria!
Una vez que haya reemplazado la palabra clave estándar pick
(que significa “tomar el compromiso tal cual”) con su palabra clave de acción preferida, puede simplemente guardar y cerrar la ventana.
Después de hacerlo, se abrirá una nueva ventana de editor que contiene el mensaje de compromiso actual. Finalmente, podemos hacer lo que nos propusimos hacer en un principio: editar este mensaje de compromiso antiguo!
Después de realizar nuestro cambio y luego guardar y cerrar la ventana del editor, la sesión de rebase interactivo está completa, ¡y nuestro mensaje de compromiso está actualizado! 🎉
Eliminando un Compromiso No Deseado
El rebase interactivo también te permite eliminar un antiguo commit de tu historia que ya no necesitas (o quieres). Imagina que accidentalmente incluiste una contraseña personal en un commit reciente: información sensible como esta no debería, en la mayoría de los casos, estar incluida en una base de código.
También recuerda que simplemente eliminando la información y cometiendo de nuevo no resuelve realmente tu problema: esto significaría que la contraseña aún está guardada en el repositorio, en forma de tu antiguo commit. Lo que realmente deseas es limpiamente y completamente eliminar este fragmento de datos del repositorio por completo!
Comencemos determinando el commit base para nuestra sesión de rebase interactivo. Como necesitamos comenzar al menos en el padre del commit malo, estamos usando el commit “Optimizar estructura de marcado…” como nuestra base:
$ git rebase -i 6bcf266b
Observa que, esta vez, he usado un hash SHA-1 concreto en el comando git rebase -i
. En lugar del hash del commit, por supuesto, podría haber usado HEAD~2
para dirigirme a ese commit.
Después de ejecutar este comando, nuevamente nos encontramos con una lista de commits.
Esta vez, estamos usando la palabra clave de acción drop
para deshacernos del commit no deseado. Alternativamente, en este caso especial, también podríamos simplemente eliminar la línea entera del editor. Si una línea (que representa un commit) ya no está presente al guardar y cerrar la ventana, Git eliminará el commit respectivo.
Sin importar cómo lo elijas hacer, después de guardar y cerrar la ventana del editor, el commit será eliminado de la historia de tu repositorio!
Combinando Múltiples Commits en Uno
Otra situación en la que se puede utilizar el rebase interactivo es cuando deseas combinar múltiples commits separados en uno solo. Antes de adentrarnos en cómo funciona esto, dediquemos unos momentos a hablar sobre cuándo o por qué esto podría ser valioso.
En general, hacer que los commits sean “más grandes” (combinando varios en uno) no es una buena estrategia en la mayoría de los casos. La regla general es mantener los commits lo más pequeños posible, porque “pequeño” significa “más fácil de leer y entender”. Sin embargo, hay situaciones en las que esto puede tener sentido. Aquí hay dos ejemplos:
- Imagina que descubres un problema con un commit más antiguo. Podrías entonces proceder a crear un nuevo commit que solucione el problema. En tal situación, poder combinar estos commits en uno solo tiene mucho sentido: el commit más reciente, después de todo, fue solo un “empaste” para solucionar un problema que no debería haber estado allí en primer lugar. Al combinar estos commits, parece que nunca hubo un problema en primer lugar!
- Otro ejemplo es cuando notas que lo has hecho un poco demasiado granular. Hacer commits pequeños está muy bien, pero esparcir tu historial de commits con muchos demasiado pequeños commits significaría exceder el objetivo.
La justificación es la misma en ambos ejemplos: al combinar dos (o múltiples) commits que deberían haber sido uno solo desde el principio, estás produciendo un historial de commits más limpio y legible!
Vamos a recorrer juntos un ejemplo práctico y tomemos la situación que se muestra a continuación como nuestro punto de partida.
Digamos que, semánticamente, tiene más sentido que estos dos commits sean uno solo. Utilizando la herramienta squash
de rebase interactivo, podemos combinarlos:
$ git rebase -i HEAD~3
A estas alturas, ya estás acostumbrado a lo que sucede a continuación: se abre una ventana de editor con una lista de commits.
I already mentioned that we’re going to use the squash
action keyword in this case. There’s an important thing to know about how squash
works: the line you mark up with the keyword will be combined with the line directly above! This explains why I marked line 2 with the squash
keyword in our example.
Después de guardar y cerrar esta ventana, se abrirá una nueva. Esto se debe a que, al combinar múltiples commits, estamos creando uno nuevo. Y este necesita un mensaje de confirmación, como cualquier otro commit, ¡también!
Lo que ves en la captura de pantalla anterior es lo que Git preparó para nosotros: combinó los mensajes de confirmación de los commits originales respectivos junto con algunos comentarios. Puedes eliminar los mensajes antiguos y comenzar de nuevo, o mantenerlos y agregar más información.
Después de guardar y cerrar esta ventana de editor, podemos afirmar con orgullo: lo que solía ser dos commits separados ahora es uno solo!
Aprovechando el poder del rebase interactivo
I hope you agree that Git’s interactive rebase tools can be very valuable! As developers, it’s important for us to strive for a clean and clear commit history. It’s a crucial ingredient in keeping a codebase healthy and easy to understand (both for your teammates, and yourself, after some time has passed).
Si quieres aprender más, recomiendo encarecidamente el “Botiquín de Primeros Auxilios para Git”. Es una colección (gratuita) de videos cortos que te muestran cómo limpiar y deshacer errores en Git.
¡Diviértete!
Preguntas Frecuentes (FAQs) sobre Rebase Interactivo de Git
¿Cuál es la diferencia entre Git Rebase y Git Merge?
Git Rebase y Git Merge son dos formas diferentes de integrar cambios de una rama en otra. Git Merge es una forma directa de combinar código de dos ramas diferentes. Crea un nuevo commit en la historia, preservando el orden cronológico de los commits. Por otro lado, Git Rebase es una forma de mover o combinar una secuencia de commits a un nuevo commit base. Es como decir “Quiero basar mis cambios en lo que todos los demás han hecho”. En otras palabras, te permite colocar los cambios de la rama actual en la parte superior de otra rama.
¿Cómo puedo deshacer un Git Rebase?
Si deseas deshacer un Git Rebase, puedes usar el comando git reflog
para encontrar el commit al que deseas regresar, y luego usar el comando git reset --hard HEAD@{number}
. El comando git reflog
muestra una lista de todos los cambios realizados en el HEAD, y el comando git reset
te permite establecer el HEAD actual en el estado especificado.
¿Cuál es el propósito de Git Interactive Rebase?
Git Interactive Rebase te permite alterar commits de muchas maneras, como editarlos, eliminarlos y fusionarlos. No solo puedes cambiar el mensaje del commit, sino que también puedes cambiar el código real si cometiste un error. Es una herramienta poderosa que te da un control completo sobre la historia de commits de tu proyecto.
¿Cómo puedo fusionar commits usando Git Interactive Rebase?
Comprimir es el acto de combinar varios commits en uno. En Git, puedes comprimir commits usando el comando git rebase -i
seguido del hash del commit que deseas comprimir. En el editor de texto que se abre, puedes marcar los commits que deseas comprimir reemplazando pick
con squash
o s
junto a cada commit.
¿Cuáles son los riesgos de usar Git Interactive Rebase?
Aunque Git Interactive Rebase es una herramienta poderosa, puede ser peligroso si no se usa correctamente. Reescribe la historia de los commits, lo cual puede ser problemático si estás trabajando en una rama pública en la que también están trabajando otros. Se recomienda usarlo en ramas locales que aún no se hayan enviado.
¿Cómo puedo resolver conflictos durante un Git Rebase?
Durante un rebase, pueden ocurrir conflictos. Git se detendrá y te permitirá resolver esos conflictos antes de continuar. Puedes resolver conflictos editando los archivos para corregir los cambios conflictivos y luego agregar los archivos resueltos con git add
. Después de resolver todos los conflictos, puedes continuar con el rebase usando git rebase --continue
.
¿Puedo usar Git Interactive Rebase para dividir un commit?
Sí, puedes usar Git Interactive Rebase para dividir un commit en varios más pequeños. Esto puede ser útil si has realizado varios cambios en un solo commit pero luego decides que deberían haber sido commits separados.
¿Cómo puedo editar un mensaje de commit usando Git Interactive Rebase?
Puedes editar un mensaje de confirmación durante un rebase interactivo. En la lista de confirmaciones, reemplaza pick
con reword
o r
junto a la confirmación que deseas editar. Cuando continúes, Git abrirá un editor de texto para cada confirmación marcada con reword
, permitiéndote cambiar el mensaje de confirmación.
¿Cuál es la diferencia entre Git Rebase y Git Pull?
Git Pull es un comando que obtiene cambios de un repositorio remoto y los fusiona en tu rama actual. Por otro lado, Git Rebase es un comando que mueve o combina una secuencia de confirmaciones a una nueva confirmación base. Aunque ambos comandos se utilizan para integrar cambios, lo hacen de maneras diferentes.
¿Puedo usar Git Interactive Rebase para cambiar el orden de las confirmaciones?
Sí, puedes cambiar el orden de las confirmaciones usando Git Interactive Rebase. En la lista de confirmaciones, simplemente puedes cambiar el orden de las líneas para cambiar el orden de las confirmaciones. Esto puede ser útil si deseas hacer que tu historial de confirmaciones sea más lógico o claro.
Source:
https://www.sitepoint.com/git-interactive-rebase-guide/