Buscar..


Sintaxis

  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
  • git rebase --continue | --skip | --abort | --edit-todo

Parámetros

Parámetro Detalles
--continuar Reinicie el proceso de rebasado después de haber resuelto un conflicto de fusión.
--abortar Abortar la operación de rebase y restablecer HEAD a la rama original. Si se proporcionó la rama cuando se inició la operación de rebase, entonces HEAD se restablecerá a la rama. De lo contrario, HEAD se restablecerá donde estaba cuando se inició la operación de rebase.
- mantener vacío Mantener los compromisos que no cambien nada de sus padres en el resultado.
--omitir Reinicie el proceso de rebasado omitiendo el parche actual.
-m, --merge Utilice las estrategias de fusión para rebase. Cuando se utiliza la estrategia de fusión recursiva (predeterminada), esto permite que la rebase tenga en cuenta los cambios de nombre en el lado ascendente. Tenga en cuenta que una fusión de rebase funciona al reproducir cada confirmación desde la rama de trabajo en la parte superior de la rama ascendente. Debido a esto, cuando ocurre un conflicto de fusión, el lado que se informa como el nuestro es la serie hasta ahora rebasada, que comienza con el flujo ascendente, y la suya es la rama de trabajo. En otras palabras, los lados se intercambian.
--estado Muestre una diferencia de lo que cambió en sentido ascendente desde la última actualización. El diffstat también es controlado por la opción de configuración rebase.stat.
-x, --exec command Realice rebase interactivo, deteniéndose entre cada command y ejecutando el command

Observaciones

Tenga en cuenta que rebase reescribe efectivamente el historial del repositorio.

Los cambios de conversión que existen en el repositorio remoto podrían reescribir los nodos del repositorio utilizados por otros desarrolladores como nodo base para sus desarrollos. A menos que sepa realmente lo que está haciendo, es una buena práctica volver a hacer una fase antes de impulsar sus cambios.

Rebase de sucursales locales

Rebasar vuelve a aplicar una serie de confirmaciones sobre otra confirmación.

Para rebase una rama, rebase la rama y luego rebase a rebase en la parte superior de otra rama.

git checkout topic
git rebase master  # rebase current branch onto master branch

Esto causaría:

      A---B---C topic
     /
D---E---F---G master

Convertirse en:

              A'--B'--C' topic
             /
D---E---F---G master

Estas operaciones se pueden combinar en un solo comando que verifica la rama y la rebasa de inmediato:

git rebase master topic   # rebase topic branch onto master branch

Importante: Después de la rebase, las confirmaciones aplicadas tendrán un hash diferente. No debe volver a generar las confirmaciones que ya haya enviado a un host remoto. Una consecuencia puede ser una incapacidad para git push su sucursal local a un host remoto, dejando su única opción para git push --force .

Rebase: nuestro y el de ellos, local y remoto.

Una rebase cambia el significado de "nuestro" y "suyo":

git checkout topic
git rebase   master    # rebase topic branch on top of master branch

Lo que apunta HEAD es "nuestro"

Lo primero que hace una rebase es reiniciar la HEAD para master ; antes de realizar un picking desde el topic rama anterior a uno nuevo (todos los mensajes de la rama del topic anterior se volverán a escribir y se identificarán con un hash diferente).

Con respecto a las terminologías utilizadas por las herramientas de combinación (no debe confundirse con la referencia local o la referencia remota )

=> local is master ("ours"),
=> remote is topic ("theirs")

Eso significa que una herramienta de combinación / diferenciación presentará la rama en sentido ascendente como local ( master : la rama en la parte superior de la cual se está rebasando), y la rama en funcionamiento como remote ( topic : la rama que se está rebasando)

+-----------------------------------------+
| LOCAL:master |    BASE   | REMOTE:topic |
+-----------------------------------------+
|             MERGED                      |
+-----------------------------------------+

Inversión ilustrada

En una fusión:

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

No cambiamos el topic sucursal actual, por lo que todavía tenemos en qué estábamos trabajando (y nos fusionamos de otra sucursal)

c--c--x--x--x---------o(*)  MERGE, still on branch topic
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              theirs

En una rebase:

¡Pero en una rebase cambiamos de lado porque lo primero que hace una rebase es retirar la rama ascendente para reproducir las confirmaciones actuales sobre ella!

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- upstream branch

Una git rebase upstream primero establecerá HEAD en la rama en sentido ascendente, de ahí el cambio de 'nuestro' y 'de ellos' en comparación con la rama de trabajo "actual" anterior.

c--c--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- set HEAD to this commit, to replay x's on it
               ^       this will be the new "ours"
               |
            upstream      

El rebase luego reproducirá "sus" confirmaciones en la nueva rama del topic "nuestro":

c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
    \
     \
      \--y--y--y--x'--x'--x'(*) <- topic  once all x's are replayed,
               ^                      point branch topic to this commit
               |
        upstream branch

Rebase interactivo

Este ejemplo pretende describir cómo se puede utilizar git rebase en modo interactivo. Se espera que uno tenga una comprensión básica de qué es git rebase y qué hace.

La rebase interactiva se inicia usando el siguiente comando:

git rebase -i

La opción -i refiere al modo interactivo . Al usar la rebase interactiva, el usuario puede cambiar los mensajes de confirmación, así como reordenar, dividir y / o confinar (combinar en uno) las confirmaciones.

Digamos que quieres reorganizar tus últimas tres confirmaciones. Para ello puedes ejecutar:

git rebase -i HEAD~3

Después de ejecutar las instrucciones anteriores, se abrirá un archivo en su editor de texto donde podrá seleccionar cómo se rebasarán sus compromisos. Para el propósito de este ejemplo, simplemente cambie el orden de sus confirmaciones, guarde el archivo y cierre el editor. Esto iniciará una rebase con el orden que has aplicado. Si verifica el git log , verá sus confirmaciones en el nuevo orden que especificó.

Regrabando mensajes de cometer

Ahora, ha decidido que uno de los mensajes de confirmación es vago y desea que sea más descriptivo. Examinemos las últimas tres confirmaciones usando el mismo comando.

git rebase -i HEAD~3

En lugar de reorganizar la orden, las confirmaciones se cambiarán de base, esta vez cambiaremos la pick , la pick predeterminada, para reword a reword una confirmación en la que desea cambiar el mensaje.

Cuando cierre el editor, se iniciará la rebase y se detendrá en el mensaje de confirmación específico que desea modificar. Esto te permitirá cambiar el mensaje de confirmación a lo que desees. Después de que haya cambiado el mensaje, simplemente cierre el editor para continuar.

Cambiando el contenido de un commit

Además de cambiar el mensaje de confirmación, también puede adaptar los cambios realizados por la confirmación. Para hacerlo solo cambia la pick para edit para una confirmación. Git se detendrá cuando llegue a ese compromiso y proporcionará los cambios originales del compromiso en el área de preparación. Ahora puede adaptar esos cambios anulando o agregando nuevos cambios.

Tan pronto como el área de preparación contenga todos los cambios que desea en ese compromiso, confirme los cambios. El mensaje de confirmación anterior se mostrará y se puede adaptar para reflejar la confirmación nueva.

Dividiendo un solo commit en multiples

Supongamos que ha realizado un compromiso pero decidió en un momento posterior que este compromiso podría dividirse en dos o más compromisos en su lugar. Usando el mismo comando que antes, reemplaza pick con edit lugar y pulsa enter.

Ahora, git se detendrá en la confirmación que ha marcado para editar y colocará todo su contenido en el área de preparación. Desde ese punto, puede ejecutar git reset HEAD^ para colocar la confirmación en su directorio de trabajo. Luego, puede agregar y confirmar sus archivos en una secuencia diferente; en última instancia, dividir una única confirmación en n confirmaciones.

Aplastando múltiples compromisos en uno

Supongamos que ha realizado algún trabajo y tiene múltiples confirmaciones que, en su opinión, podrían ser una única confirmación. Para eso puedes llevar a cabo git rebase -i HEAD~3 , reemplazando 3 con una cantidad apropiada de confirmaciones.

Esta vez reemplaza pick con squash lugar. Durante la rebase, la confirmación que has ordenado aplastar se aplastará sobre la confirmación anterior; convirtiéndolos en un solo compromiso en su lugar.

Abortar una rebase interactiva

Has iniciado una rebase interactiva. En el editor donde selecciona sus confirmaciones, decide que algo va mal (por ejemplo, falta una confirmación o si eligió el destino incorrecto de la rebase), y desea abortar la rebase.

Para hacer esto, simplemente elimine todas las confirmaciones y acciones (es decir, todas las líneas que no comiencen con el signo # ) y la rebase se cancelará.

El texto de ayuda en el editor en realidad proporciona esta sugerencia:

# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out

Empujando después de una rebase

A veces necesitas volver a escribir el historial con una rebase, pero git push queja de hacerlo porque reescribiste el historial.

Esto se puede resolver con un git push --force , pero considere git push --force-with-lease , que indica que desea que el empuje falle si la rama local de seguimiento remoto difiere de la rama del remoto, por ejemplo, alguien otra cosa empujó al mando a distancia después de la última búsqueda. Esto evita sobrescribir inadvertidamente el empuje reciente de otra persona.

Nota : git push --force - e incluso - --force-with-lease para el caso - puede ser un comando peligroso porque reescribe el historial de la rama. Si otra persona había tirado de la rama antes del empuje forzado, su git pull o git fetch tendrá errores porque la historia local y la historia remota están divergidas. Esto puede hacer que la persona tenga errores inesperados. Si miramos lo suficiente a los reflogs, el trabajo del otro usuario puede recuperarse, pero puede llevar a una gran cantidad de tiempo perdido. Si debe realizar un impulso forzado a una sucursal con otros colaboradores, intente coordinar con ellos para que no tengan que lidiar con los errores.

Rebase hasta la confirmación inicial

Desde Git 1.7.12 es posible cambiar de base a la confirmación de la raíz. La confirmación de la raíz es la primera confirmación realizada en un repositorio, y normalmente no se puede editar. Usa el siguiente comando:

git rebase -i --root

Rebasar antes de una revisión de código

Resumen

Este objetivo es reorganizar todos sus compromisos dispersos en compromisos más significativos para revisiones de código más fáciles. Si hay demasiadas capas de cambios en demasiados archivos a la vez, es más difícil hacer una revisión del código. Si puede reorganizar sus confirmaciones creadas cronológicamente en confirmaciones tópicas, entonces el proceso de revisión del código es más fácil (y posiblemente menos errores se escapen a través del proceso de revisión del código).

Este ejemplo demasiado simplificado no es la única estrategia para usar git para hacer mejores revisiones de código. Es la forma en que lo hago, y es algo que inspira a otros a considerar cómo hacer que las revisiones de códigos y el historial de Git sean más fáciles / mejores.

Esto también demuestra pedagógicamente el poder de rebase en general.

Este ejemplo asume que usted sabe acerca de rebases interactivos.


Asumiendo:

  • estás trabajando en una función de rama de maestro
  • su función tiene tres capas principales: front-end, back-end, DB
  • ha realizado muchos compromisos mientras trabajaba en una rama de características. Cada compromiso toca varias capas a la vez.
  • quieres (al final) solo tres confirmaciones en tu rama
    • uno que contiene todos los cambios frontales
    • uno que contiene todos los cambios de back-end
    • uno que contiene todos los cambios de DB

Estrategia:

  • Vamos a cambiar nuestros compromisos cronológicos en compromisos "tópicos".
  • Primero, divida todas las confirmaciones en múltiples confirmaciones más pequeñas, cada una de las cuales contiene solo un tema a la vez (en nuestro ejemplo, los temas son front-end, back-end, cambios de base de datos)
  • Luego reordene nuestros compromisos tópicos juntos y 'aplaste' en un solo tópico comprometido

Ejemplo:

$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master

Esto se mostrará en el editor de texto:

pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb

Cambia esto a esto:

e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb

Entonces git aplicará un commit a la vez. Después de cada confirmación, se mostrará un mensaje y, a continuación, puede hacer lo siguiente:

Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
 M db.sql
 M page.html
$ git add db.sql  #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue

Luego repetirás esos pasos para cada commit. Al final, tienes esto:

$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql

Ahora ejecutamos rebase una vez más para reordenar y aplastar:

$ git rebase -i master

Esto se mostrará en el editor de texto:

pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb

Cambia esto a esto:

pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s  3264de2 adding todo items: page.html

AVISO: asegúrese de decirle a git rebase que aplique / aplaste las confirmaciones tópicas más pequeñas en el orden en que fueron comprometidas cronológicamente . De lo contrario, podría tener conflictos de fusión falsos e innecesarios con los que lidiar.

Cuando esa rebase interactiva está todo dicho y hecho, obtienes esto:

$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer

Resumen

Ahora ha rebasado sus compromisos cronológicos en compromisos tópicos. En la vida real, es posible que no tenga que hacer esto cada vez, pero cuando quiera o necesite hacerlo, ahora puede hacerlo. Además, espero que hayas aprendido más sobre git rebase.

Configurar git-pull para realizar automáticamente una rebase en lugar de una fusión

Si su equipo está siguiendo un flujo de trabajo basado en rebase, puede ser una ventaja configurar git para que cada rama recién creada realice una operación de rebase, en lugar de una operación de fusión, durante un git pull .

Para configurar cada nueva rama para volver a generar automáticamente, agregue lo siguiente a su .gitconfig o .git/config :

[branch]
autosetuprebase = always

Línea de comando: git config [--global] branch.autosetuprebase always

Alternativamente, puedes configurar el comando git pull para que siempre se comporte como si se pasara la opción --rebase :

[pull]
rebase = true

Línea de comando: git config [--global] pull.rebase true

Probando todas las confirmaciones durante el rebase

Antes de realizar una solicitud de extracción, es útil asegurarse de que la compilación sea exitosa y que las pruebas se aprueben para cada confirmación en la rama. Podemos hacerlo automáticamente usando el parámetro -x .

Por ejemplo:

git rebase -i -x make

realizará la rebase interactiva y se detendrá después de cada confirmación de ejecución de make . En caso de make falle, git se detendrá para darle la oportunidad de solucionar los problemas y enmendar el compromiso antes de continuar con la selección del siguiente.

Configurando autostash

Autostash es una opción de configuración muy útil cuando se usa rebase para cambios locales. A menudo, es posible que tenga que traer confirmaciones de la rama ascendente, pero todavía no está listo para comprometerse.

Sin embargo, Git no permite que se inicie una rebase si el directorio de trabajo no está limpio. Autostash al rescate:

git config --global rebase.autostash    # one time configuration
git rebase @{u}                         # example rebase on upstream branch

El autostash se aplicará cada vez que finalice la rebase. No importa si la rebase finaliza correctamente o si se cancela. De cualquier manera, se aplicará el autostash. Si la reorganización fue exitosa, y el compromiso de base por lo tanto cambió, entonces puede haber un conflicto entre el autostash y los nuevos compromisos. En este caso, tendrá que resolver los conflictos antes de cometer. Esto no es diferente de si lo hubieras escondido manualmente y luego lo hubieras aplicado, por lo que no hay inconveniente en hacerlo automáticamente.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow