Comprender y memorizar los parámetros de git rebase

11

Hasta ahora, la parte más confusa de git es rebase en otra rama. Específicamente, son los argumentos de la línea de comandos los que son confusos.

Cada vez que quiero volver a crear una pequeña parte de una rama en la punta de otra, tengo que revisar la documentación de git rebase y me lleva unos 5-10 minutos entender cuáles deberían ser los tres argumentos principales.

git rebase <upstream> <branch> --onto <newbase>

¿Cuál es una buena regla general para ayudarme a memorizar a qué se debe configurar cada uno de estos 3 parámetros, dado cualquier tipo de rebase en otra rama?

Tenga en cuenta que he revisado la documentación de git-rebase una y otra vez, una y otra vez, y otra vez (y otra vez), pero siempre es difícil de entender (como un libro blanco científico aburrido o algo así). Entonces, en este punto, siento que necesito involucrar a otras personas para que me ayuden a comprenderlo.

Mi objetivo es que nunca debería tener que revisar la documentación de estos parámetros básicos. No he podido memorizarlos hasta ahora, y ya he hecho un montón de rebases. Por lo tanto, es un poco inusual que haya podido memorizar todos los demás comandos y sus parámetros hasta ahora, pero no rebase --onto.

void.pointer
fuente
Puede definir algunos alias de git para sus casos de uso comunes o activar un script de asistente que le recuerda lo que significa cada uno de los parámetros antes de ejecutar el comando.
Rory Hunter
44
Ah, estas alucinantes, pura elegancia de las opciones de comando git. Tan intuitivo de usar. Siempre un verdadero placer.
JensG

Respuestas:

9

Saltemos --ontopor el momento. upstreamy branchson bastante básicos, y en realidad son una especie de imitación checkouty branch- el segundo argumento es opcional:

git branch <newbranch>
git branch <newbranch> <base>
git checkout -b <newbranch>
git checkout -b <newbranch> <base>
git rebase <upstream>
git rebase <upstream> <branch>

(Aparte, los nombres de estos argumentos en rebase"rama", "aguas arriba" y no son muy descriptivos OMI Me suelen pensar en ellos como peachoftree,. <start>Y <end>, que es lo que va a utilizar ellos: git rebase <start> <end>)

Cuando se omite la segunda rama, el resultado es casi el mismo que primero verificando esa rama y luego haciéndolo como si no hubiera especificado esa rama. La excepción es branchque no cambia su rama actual:

git checkout <base> && git branch <newbranch> && git checkout <previous_branch>
git checkout <base> && git checkout -b <newbranch>
git checkout <end>  && git rebase <start>

En cuanto a entender qué rebasehace cuando se invoca, primero comencé a pensar en ello como un tipo especial de fusión. En realidad no lo es, pero ayudó cuando comencé a entender rebase. Para tomar prestado el ejemplo de peachoftree:

A--B--F--G master
    \
     C--D--E feature

A git merge masterresulta en esto:

A--B--F-----G master
    \        \
     C--D--E--H feature

Mientras que un git rebase master(¡mientras está en la rama feature!) Da como resultado esto:

A--B--F--G master
          \
           C'--D'--E' feature

En ambos casos, featureahora contiene código de ambos mastery feature. Si no está activado feature, el segundo argumento se puede usar para cambiar a él como un acceso directo: git rebase master featurehará lo mismo que antes.


Ahora, para el especial --onto. La parte importante a recordar con esto es que su valor predeterminado es <start>si no se especifica. Entonces, si especifiqué --ontoespecíficamente, esto resultaría en lo mismo:

git rebase --onto master master
git rebase --onto master master feature

(No uso --ontosin especificar <end>simplemente porque es más fácil analizar mentalmente, incluso si esos dos son iguales si ya están activados feature).

Para ver por qué --ontoes útil, aquí hay un ejemplo diferente. Digamos que estaba encendido featurey noté un error, que luego comencé a solucionar, pero que se bifurcó en featurelugar de masterpor error:

A--B--F--G master
    \
     C--D--E feature
            \
             H--I bugfix

Lo que quiero es "mover" estas confirmaciones para bugfixque ya no dependan de ellas feature. Tal como está, cualquier tipo de fusión o rebase que se muestra arriba en esta respuesta tomará los tres featurecommits junto con los dos bugfixcommits.

Por ejemplo, git rebase master bugfixestá mal. La gama <start>de <end>pasa a incluir todas las confirmaciones de featureque se reproducen en la parte superior de master:

A--B--F--G master
    \     \
     \     C'--D'--E'--H'--I' bugfix
      \
       C--D--E feature

Lo que realmente queremos es el rango de confirmaciones de featureque bugfixpara que se reproduzca en la parte superior de master. Para eso --ontoestá: especificar un objetivo de "repetición" diferente al de la rama "inicio":

git rebase --onto master feature bugfix

A--B--F--G master
    \     \
     \     H'--I' bugfix
      \
       C--D--E feature
Izkata
fuente
1

Solo un repaso, el rebase es principalmente para cuando desea que su historial de confirmación parezca lineal si dos ramas se han desarrollado independientemente una de la otra, básicamente reescribe el historial de confirmación.

la forma en que me gusta hacerlo es git rebase --onto <target branch> <start branch> <end branch>

¿Dónde <target branch>está la rama sobre la que está rebasando? <start branch>Normalmente es la rama de la que se <end branch>divide y <end branch>es la rama sobre la que está rebase.

si comienzas con

A--B--F--G master
    \
     C--D--E feature

y hacer

git rebase --onto master master feature

conseguirás

A--B--F--G master
          \
           C'--D'--E' feature

Otra cosa buena que debes saber es que el valor <target branch>predeterminado es <start branch>para que puedas hacer ese mismo rebase que

git rebase --onto master feature

si necesita más ayuda, consulte la guía Rebase sin lágrimas

melocotón
fuente
Su resultado parece engañoso. rebase debe dejar la masterrama en sí sin cambios. Solo obtienes 'característica' para ramificarse como G--C'--D'--E'mientras mastertodavía se detiene en G.
Frank
@ Frank, hice eso para enfatizar todo el asunto de la historia lineal, pero ahora creo que tu camino es mejor. fijo.
peachoftree
1
¿Puedes mostrar un ejemplo de dónde <target branch>y qué <start branch>son diferentes para ayudar a los lectores a comprender el caso más general?
Rufflewind