Git cambia la rebase

Tengo 3 twigs: maestro, function, corrección de errores … Y las confirmaciones se ven así:

4-5-6(feature) | 1-2-3(master) | 7(bugfix) 

Hice "git rebase bugfix feature" para probar mi function con corrección de errores

  1-2-3(master) | 7(bugfix)-4-5-6(feature) 

Ahora necesito volver a crear la database para crear una request de extracción para mi twig de funciones sin la corrección de errores, así que hice "git rebase master feature" y espero:

 1-2-3(master)-4-5-6(feature) | 7(bugfix) 

En cambio, dice que la function está actualizada con el maestro. Eso es cierto, pero no quiero fusionar commit 7 allí. Podría hacer una rebase interactiva y eliminar esa confirmación, pero me gustaría saber si hay una mejor manera de hacerlo. Pensé que rebase solo llevaría las confirmaciones de una twig a otra, pero parece que no lo es.

Algo de lo que debemos darnos count es que rebase no reescribe el historial ni mueve las confirmaciones, las confirmaciones en Git no pueden modificarse. En cambio, crea una nueva historia y dice que fue así todo el time. Por ejemplo, cuando comienzas con:

  4-5-6(feature) | 1-2-3(master) | 7(bugfix) 

Y luego, la function git rebase bugfix feature lo que realmente sucede es esto:

  4-5-6 | 1-2-3(master) | 7(bugfix)-4A-5A-6A(feature) 

Se realizan tres nuevos commits, 4A, 5A y 6A. Los commits originales aún están allí, pero no hay nada que los señale. Eventualmente serán limpiados, pero permanecerán allí por varios días.

Eso significa que puedes deshacer una rebase, que es lo que intentas hacer. Deberá encontrar dónde estaba la feature justo antes de la rebase. Eso se puede hacer con git reflog que rastrea cada vez que HEAD mueve. Eso ocurre con el checkout , la commit , el reset y la rebase . git reflog puede ser algo así como:

 65e93ca (HEAD -> feature) HEAD@{0}: rebase finished: returning to refs/heads/feature 65e93ca (HEAD -> feature) HEAD@{1}: rebase: 3 feature 6d539a3 HEAD@{2}: rebase: 2 feature 3cd634f HEAD@{3}: rebase: 1 feature b84924b (bugfix) HEAD@{4}: rebase: checkout bugfix a9fd2f1 HEAD@{5}: commit: 3 feature 29136bc HEAD@{6}: commit: 2 feature 60543b0 HEAD@{7}: commit: 1 feature c487530 (master) HEAD@{8}: checkout: moving from master to feature 

Eso me dice que a9fd2f1 fue la última confirmación en la function antes de que se vuelva a configurar. En lugar de volver a hacer la rebase, puedo volver a mover la function.

 git checkout feature git reset --hard a9fd2f1 

En el futuro, este tipo de cosas se hace mucho más fácil si se git tag la position original de la function antes de hacer la rebase. Luego puede volver a configurar esa label sin tener que search en el reflog.


En cuanto a su problema específico, el problema es que después de la rebase su repository ahora se ve así:

 6A [feature] | 5A | 4A | 7 [bugfix] | 3 [master] | 2 | 1 

Cuando le preguntas a git rebase master feature Git nota que el maestro ya es un ancestro de la function y no hace nada. No importa que la corrección de errores esté en el medio.

En su lugar, debe decirle a Git que desea volver a establecer la database solo 4A, 5A y 6A e ignorar 7. Esto se hace usando la syntax --onto .

 git rebase --onto master bugfix feature 

Eso dice que se rebase desde, pero sin include, la corrección de errores para incorporar al maestro.

Yo recomendaría usar git reset lugar de intentar rehacer la rebase. No hay garantía de que la segunda rebase salga igual, especialmente si hubo conflictos. Mientras que con el git reset estás volviendo explícitamente al estado anterior del repository.

Pensé que rebase solo llevaría las confirmaciones de una twig a otra, pero parece que no lo es.

Esta es la key: su compromiso 7 en su diagtwig está en la feature twig. También está en la bugfix twig. Los compromisos 1-2-3 están en las tres twigs.

Las twigs de Git son muy diferentes de la mayoría de los otros sistemas de control de versiones. Una twig "contiene" una confirmación solo en virtud de poder "alcanzar" esa confirmación desde la confirmación a la que apunta el nombre de la sucursal. Los nombres de twig como master , bugfix y feature simplemente apuntan a una confirmación particular , que Git llama la punta de la twig. Son los compromisos mismos los que forman una cadena, haciendo que cada uno comprometa "punto atrás" con su pnetworkingecesor.

Debido a esto, git rebase realidad copy commits: git rebase de:

  4--5--6 <-- feature / 1--2--3 <-- master \ 7 <-- bugfix 

a:

  4--5--6 [abandoned - used to be feature] / 1--2--3 <-- master \ 7 <-- bugfix \ D--E--F <-- feature 

donde D es una copy del original 4 , E es una copy de 5 , y F es una copy de 6 (utilicé las letras 4ta, 5ta y 6a aquí para poder copyr 7 a G por ejemplo, si quisiéramos, pero esta técnica está a punto de agotarse).

Sin embargo, puedes get lo que quieres. Solo necesita copyr DEF nuevamente , o -esto es probablemente mejor para este caso particular- simplemente regrese al 4-5-6 original, abandonado.

Cuando usas git rebase para copyr commits, los originales se quedan. Hay dos nombres mediante los cuales puede encontrarlos: ORIG_HEAD , y los nombres de reflog . El nombre ORIG_HEAD es sobrescrito por varios otros commands, pero puede verificar si aún apunta a cometer 6 :

 git log ORIG_HEAD 

y probablemente reconocerás tus originales.

Los nombres de los reflog tienen el name @{ number } del formulario name @{ number } , por ejemplo, la feature@{1} . La parte del number aumenta cada vez que cambia la confirmación a la que apunta la parte del name , ya que Git simplemente guarda el valor actual del name en el reflog, empujando el rest hasta una muesca.

Por lo tanto:

 git log feature@{1} 

debe mostrarle las mismas confirmaciones que git log ORIG_HEAD , excepto que la feature@{1} permanece por más time (tal vez convirtiéndose en la feature@{2} , feature@{3} , y así sucesivamente, con el time). De forma pnetworkingeterminada, los valores anteriores para cada nombre se guardan durante al less 30 días, por lo que debería ser suficiente time para recuperarlo.

Para recuperarlo, utilice la git reflog feature para ver qué número va en la parte @{...} y luego, mientras está en la feature ( git checkout feature ), ejecute:

 git reset --hard feature@{1} 

o cualquiera que sea el número (aunque verificar una vez más con git log primero es una buena idea).

(Esto supone que no tiene nada que controlar, es decir, que el git status dice que todo está limpio, porque el git reset --hard borra los cambios del índice y del tree de trabajo aún no registrados).