el comando git rebase tiene una reputación de ser mágico git voodoo del que los principiantes deben mantenerse alejados, pero en realidad puede hacer la vida mucho más fácil para un equipo de desarrollo cuando se usa con cuidado. En este artículo, compararemos git rebase con el comando git merge relacionado e identificaremos todas las oportunidades potenciales para incorporar el reajuste en el flujo de trabajo típico de Git.,

Descripción Conceptual

Lo primero que hay que entender acerca degit rebasees que resuelve el mismo problema quegit merge. Ambos comandos están diseñados para integrar los cambios de una rama en otra rama – simplemente lo hacen de maneras muy diferentes.

considere lo que sucede cuando comienza a trabajar en una nueva característica en una rama dedicada, luego otro miembro del equipo actualiza la ramamaster con nuevas confirmaciones. Esto resulta en un historial bifurcado, que debería ser familiar para cualquiera que haya utilizado Git como herramienta de colaboración.,

Ahora, digamos que el nuevo cometa en el master son relevantes para la función que se esté trabajando. Para incorporar las nuevas confirmaciones en su rama feature, tiene dos opciones: fusionar o rebasear.,

la opción Merge

la opción más fácil es combinar la rama master en la rama feature usando algo como lo siguiente:

git checkout feature git merge master

o, puede condensar esto en una sola línea:

 git merge feature master

esto crea un nuevo «merge commit» en la rama feature que une los historiales de ambas ramas, dándole una estructura de ramas que se ve así:

fusionar es bueno porque es una operación no destructiva. Las ramas existentes no se cambian de ninguna manera., Esto evita todas las trampas potenciales de la reorganización (discutidas más adelante).

por otro lado, esto también significa que la rama feature tendrá un commit de fusión extraño cada vez que necesite incorporar cambios de upstream. Si master está muy activo, esto puede contaminar bastante el historial de su rama de características. Si bien es posible mitigar este problema con las opciones avanzadas git log, puede dificultar que otros desarrolladores entiendan el historial del proyecto.,

la opción Rebase

como alternativa a la fusión, puede rebase la rama feature En master usando los siguientes comandos:

git checkout feature git rebase master

esto mueve toda la rama feature Branch para comenzar en la punta de la rama master, incorporando efectivamente todas las nuevas confirmaciones en master. Pero, en lugar de usar una confirmación merge, rebasing reescribe el historial del proyecto creando nuevas confirmaciones para cada confirmación en la rama original.,

El principal beneficio de rebasing es que obtienes un historial de proyectos mucho más limpio. Primero, elimina las confirmaciones de fusión innecesarias requeridas por git merge. En segundo lugar, como puede ver en el diagrama anterior, el cambio de base también resulta en un historial del proyecto perfectamente lineal: puede seguir la punta de feature hasta el comienzo del proyecto sin bifurcaciones. Esto hace que sea más fácil navegar sus proyectos con los comandos como git log, git bisect y gitk.,

pero, hay dos compensaciones para este prístino historial de commits: seguridad y trazabilidad. Si no sigues la regla de oro del cambio de Base, reescribir el historial del proyecto puede ser potencialmente catastrófico para tu flujo de trabajo de colaboración. Y, lo que es menos importante, el rebasing pierde el contexto proporcionado por una confirmación de fusión: no se puede ver cuándo se incorporaron los cambios de upstream a la característica.

Rebasing interactivo

El rebasing interactivo te da la oportunidad de modificar las confirmaciones a medida que se mueven a la nueva rama., Esto es incluso más poderoso que un rebase automatizado, ya que ofrece un control completo sobre el historial de Confirmaciones de la rama. Normalmente, esto se usa para limpiar un historial desordenado antes de fusionar una rama de característica en master.,

Para comenzar una sesión de rebase interactiva, pase la opción i al comando git rebase:

git checkout feature git rebase -i master

Esto abrirá un editor de texto con todas las confirmaciones que están a punto de ser movidas:

pick 33d5b7a Message for commit #1 pick 9480b3d Message for commit #2 pick 5c67e61 Message for commit #3

esta lista define exactamente cómo se verá la rama después de que se realice la rebase. Cambiando el comando pick y / o reordenando las entradas, puede hacer que el historial de la rama se vea como lo que quiera., Por ejemplo, si el 2º cometer corrige un pequeño problema en la 1ª cometer, puede condensar en un único commit con el fixup comandos:

pick 33d5b7a Message for commit #1 fixup 9480b3d Message for commit #2 pick 5c67e61 Message for commit #3

Cuando usted guarde y cierre el archivo, Git realizar el reajuste de acuerdo a sus instrucciones, resultando en un proyecto de historia que tiene el siguiente aspecto:

Eliminar insignificante compromete como este, hace su función que es la historia mucho más fácil de entender. Esto es algo que git merge simplemente no puede hacer.,

La regla de oro del Rebasing

Una vez que entiendes lo que es el rebasing, lo más importante que debes aprender es cuándo no hacerlo. La regla de oro de git rebase es nunca usarlo en ramas públicas.

Por ejemplo, pensar en qué pasaría si rebasada master en el feature rama:

El reajuste mueve todos los commits en el master en la punta de feature. El problema es que esto solo sucedió en su repositorio., Todos los demás desarrolladores siguen trabajando con el masteroriginal. Dado que el cambio de base resulta en nuevas confirmaciones, Git pensará que el historial de la rama master ha divergido del de todos los demás.

la única forma de sincronizar las dos ramas master es fusionarlas de nuevo, lo que resulta en una confirmación de fusión adicional y dos conjuntos de confirmaciones que contienen los mismos cambios (las originales y las de tu rama rebasada). Huelga decir que esta es una situación muy confusa.,

entonces, antes de ejecutargit rebase, siempre pregúntese: «¿alguien más está mirando esta rama?»Si la respuesta es sí, quite las manos del teclado y comience a pensar en una forma no destructiva de hacer sus cambios (por ejemplo, el comando git revert). De lo contrario, puedes reescribir la historia todo lo que quieras.

Force-Pushing

si intentas empujar la rama rebasada master de nuevo a un repositorio remoto, Git evitará que lo hagas porque entra en conflicto con la rama remota master., Sin embargo, puede forzar el push pasando la bandera --force, como así:

# Be very careful with this command! git push --force

esto sobrescribe la rama remota master para que coincida con la rebasada de su repositorio y hace que las cosas sean muy confusas para el resto de su equipo. Por lo tanto, tenga mucho cuidado de usar este comando solo cuando sepa exactamente lo que está haciendo.

una de las pocas veces que debería forzar el envío es cuando ha realizado una limpieza local después de haber enviado una rama de Característica privada a un repositorio remoto (por ejemplo, para fines de copia de seguridad)., Esto es como decir: «Oops, realmente no quería impulsar esa versión original de la rama de características. Tome el actual en su lugar.»Una vez más, es importante que nadie esté trabajando fuera de las confirmaciones de la versión original de la rama de características.

Tutorial del flujo de trabajo

el rebase se puede incorporar a tu flujo de trabajo de Git tanto o tan poco como tu equipo se sienta cómodo. En esta sección, echaremos un vistazo a los beneficios que el rebase puede ofrecer en las diversas etapas del desarrollo de una característica.,

el primer paso en cualquier flujo de trabajo que aproveche git rebase es crear una rama dedicada para cada característica. Esto le da la estructura de rama necesaria para utilizar de forma segura el rebase:

limpieza Local

Una de las mejores maneras de incorporar el rebase en su flujo de trabajo es limpiar las características locales en curso. Al realizar periódicamente un rebase interactivo, puede asegurarse de que cada confirmación en su función esté enfocada y sea significativa., Esto le permite escribir su código sin preocuparse por dividirlo en confirmaciones aisladas—puede arreglarlo después del hecho.

al llamar a git rebase, tiene dos opciones para la nueva base: la rama principal de la característica (por ejemplo, master), o una confirmación anterior en su característica. Vimos un ejemplo de la primera opción en la sección de rebase interactivo. La última opción es buena cuando solo necesitas arreglar las últimas confirmaciones. Por ejemplo, el siguiente comando comienza un rebase interactivo de solo las últimas 3 confirmaciones.,

git checkout feature git rebase -i HEAD~3

al especificar HEAD~3 como la nueva base, en realidad no estás moviendo la rama, solo estás reescribiendo interactivamente las 3 confirmaciones que le siguen. Tenga en cuenta que esto no incorporará los cambios en la rama feature.

Si desea reescribir toda la función utilizando este método, el comando git merge-base puede ser útil para encontrar la base original de la rama feature., Lo siguiente devuelve el ID de confirmación de la base original, que luego puede pasar a git rebase:

git merge-base feature master

Este uso del rebase interactivo es una gran manera de introducir git rebase en su flujo de trabajo, ya que solo afecta a las ramas locales. Lo único que otros desarrolladores verán es su producto terminado, que debe ser un historial de rama de características limpio y fácil de seguir.

pero de nuevo, esto solo funciona para ramas de características privadas., Si estás colaborando con otros desarrolladores a través de la misma rama de funciones, esa rama es pública y no se te permite reescribir su historial.

no hay git merge alternativa para limpiar confirmaciones locales con un rebase interactivo.

incorporar cambios ascendentes en una característica

en la sección Descripción Conceptual, vimos cómo una rama de característica puede incorporar cambios ascendentes desdemasterusandogit mergeogit rebase., La fusión es una opción segura que conserva todo el historial de su repositorio, mientras que el cambio de Base crea un historial lineal moviendo su rama de entidad a la punta de master.

este uso de git rebase es similar a una limpieza local (y se puede realizar simultáneamente), pero en el proceso incorpora los commits de master.

tenga en cuenta que es perfectamente legal rebase en una rama remota en lugar de master., Esto puede suceder cuando colaboras en la misma función con otro desarrollador y necesitas incorporar sus cambios en tu repositorio.,

por ejemplo, si usted y otro desarrollador llamado John agregaron confirmaciones a la rama feature, su repositorio podría tener el siguiente aspecto después de obtener la rama remota feature desde el repositorio de John:

puede resolver esta bifurcación exactamente de la misma manera que integra cambios desde master: combine su local feature con john/feature, o rebase su local feature en la punta de john/feature.,

tenga en cuenta que este rebase no viola la regla de oro del rebase porque solo sus Confirmaciones locales feature se están moviendo, todo lo anterior está intacto. Esto es como decir, » agrega mis cambios a lo que Juan ya ha hecho.»En la mayoría de las circunstancias, esto es más intuitivo que la sincronización con la rama remota a través de una confirmación de fusión.

de forma predeterminada, el comando git pull realiza una fusión, pero puede forzarlo a integrar la rama remota con una rebase pasándole la opción --rebase.,

revisar una función con una solicitud de extracción

Si utiliza solicitudes de extracción como parte de su proceso de revisión de código, debe evitar usar git rebase después de crear la solicitud de extracción. Tan pronto como hagas la solicitud de extracción, otros desarrolladores estarán mirando tus commits, lo que significa que es una rama pública. Reescribir su historial hará imposible que Git y tus compañeros de equipo rastreen cualquier confirmación de seguimiento agregada a la función.

Cualquier cambio de otros desarrolladores deben ser incorporados con la etiqueta git merge en lugar de git rebase.,

por esta razón, generalmente es una buena idea limpiar su código con un rebase interactivo antes de enviar su solicitud de extracción.

integrar una función aprobada

después de que su equipo haya aprobado una función, tiene la opción de cambiar la base de la función en la punta de la rama master antes de usar git merge para integrar la función en la base de código principal.,

Esta es una situación similar a la incorporación de cambios upstream en una rama feature, pero ya que no se le permite volver a escribir confirmaciones en la rama master, tiene que usar eventualmente git merge para integrar la característica. Sin embargo, al realizar un rebase antes de la fusión, está seguro de que la fusión será reenviada rápidamente, lo que resulta en un historial perfectamente lineal. Esto también te da la oportunidad de aplastar cualquier confirmación de seguimiento agregada durante una solicitud de extracción.,

Si no se siente completamente cómodo con git rebase, siempre puede realizar el rebase en una rama temporal. De esa manera, si accidentalmente estropeas el historial de tu característica, puedes revisar la rama original e intentarlo de nuevo. Por ejemplo:

git checkout feature git checkout -b temporary-branch git rebase -i master # git checkout master git merge temporary-branch

Summary

y eso es todo lo que realmente necesita saber para comenzar a reorganizar sus ramas., Si prefiere un historial limpio y lineal libre de Confirmaciones de fusión innecesarias, debe buscar git rebase en lugar de git merge al integrar cambios desde otra rama.

por otro lado, si desea preservar el historial completo de su proyecto y evitar el riesgo de reescribir confirmaciones públicas, puede seguir con git merge. Cualquier opción es perfectamente válida, pero al menos ahora tiene la opción de aprovechar los beneficios de git rebase.