stackoverflow - git pull*after*git rebase?
git rebase tutorial (4)
Cuando rebasó su rama de características en la parte superior del maestro, creó un montón de nuevas confirmaciones. Sin embargo, su rama de origin/feature
sigue apuntando a las antiguas. Esta es la situación después de la rebase:
C'' (feature)
B''
A''
* (master, origin/master)
*
*
| C (origin/feature)
| B
| A
|/
* some base commit
Mientras que la confirmación A''
contiene un conjunto de cambios similar a la confirmación A
, de ninguna manera es la misma confirmación. Contiene un árbol diferente, y tiene un padre diferente.
Ahora, cuando intenta volver a activar la feature
, intenta crear este historial:
* (feature)
|/
C''|
B''|
A''|
* | (master, origin/master)
* |
* |
| C (origin/feature)
| B
| A
|/
* some base commit
Usted está fusionando dos ramas que han introducido cambios muy similares a chorros. Esto está destinado a crear una tonelada de conflictos, además de ser totalmente inútil.
Lo que debe hacer es informar a su representante de flujo ascendente acerca de la rebase utilizando git push -f
. Esto perderá la historia antigua, y la reemplazará con la reescrita .
La alternativa es evitar el uso de git rebase
en las sucursales que ya haya git rebase
a cualquier otro repositorio, o evitar el git rebase
completo. Este es el enfoque más limpio : resulta en la historia tal como sucedió, en lugar de decir mentiras sobre la historia como lo hace git rebase
. Eso es al menos lo que prefiero.
Tengo una rama característica, y una rama maestra.
La rama maestra ha evolucionado y me refiero a hacer que esas actualizaciones se aparten lo menos posible de la rama maestra.
Así que git pull
en ambas ramas, git checkout feature/branch
y finalmente git rebase master
.
Ahora, o bien aquí espero que todo funcione correctamente o que aparezcan conflictos que debo resolver antes de continuar con la rebase hasta que todas las confirmaciones maestras se vuelvan a aplicar con éxito en la rama de características.
Ahora, lo que realmente sucedió en mi caso es algo que no entiendo:
$>git rebase master
First, rewinding head to replay your work on top of it...
Applying: myFirstCommitDoneOnTheBranch
Applying: myOtherCommitDoneOnTheBranch
$>git status
On branch feature/branch
Your branch and ''origin/feature/feature'' have diverged,
and have 27 and 2 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
$>git pull
*load of conflicts*
Ahora, por mucho que pueda entender, está cargada de conflictos después del tirón; No entiendo la necesidad de un tirón. Lógicamente, debería volver al maestro cuando se ramificó, guardar los compromisos realizados en la rama, reenviarlos al último compromiso en el maestro y luego aplicar los compromisos guardados.
No entiendo a qué se refiere el mensaje de Applying
: ¿qué es la aplicación de las confirmaciones en qué versión?
Si las versiones remotas de master
y feature/branch
están actualizadas individualmente, simplemente reinicie su rama de características local
git checkout feature/branch
git fetch origin feature/branch
git reset --hard origin/feature/branch
entonces si quieres introducir cambios en la rama master
,
git rebase origin/master
have 27 and 2 different commits each
que le origin/<yourbranch>
que ahora tiene 27 confirmaciones nuevas del master
y 2 confirmaciones nuevas en su sucursal que no están presentes en el origin/<yourbranch>
.
Debido a que el origin/<yourbranch>
ha sido modificado masivamente por la rebase, ya no tiene una base común con origin/<yourbranch>
. Por lo tanto, no desea extraer los cambios desde el origin/<yourbranch>
después de la rebase, porque, como ve, todo H *** se suelta.
Si sabe que hay cambios en el origin/<yourbranch>
que necesita en su sucursal local, tire de ellos antes de volver a armar.
Si está seguro de que nadie ha cambiado de origin/<yourbranch>
desde su último impulso (una apuesta segura si esta es su propia rama de características), puede usar push --force
para sincronizarlos nuevamente. Luego, origin/<yourbranch>
nuevamente tendrá la misma base que su sucursal local y esa base contendrá todos los últimos cambios master
.
tl; dr Debes actualizar el master
y la feature
con git pull
y git pull --rebase
antes de git pull --rebase
feature
en la parte superior del master
. No hay necesidad de hacer un git pull
después de que haya rebasado su rama de feature
en la parte superior del master
.
Con tu flujo de trabajo actual, la razón por la que el git status
está diciendo esto:
Su rama y ''origen / característica'' se han desviado, y tienen 27 y 2 confirmaciones diferentes cada una, respectivamente.
Esto se debe a que su rama de feature
rebasada ahora tiene 25 confirmaciones nuevas que no son accesibles desde el origin/feature
(ya que provienen de la base en el master
) más 2 confirmaciones que son accesibles desde el origin/feature
pero tienen diferentes ID de confirmación. Esos compromisos contienen los mismos cambios (es decir, son parches equivalentes ) pero tienen diferentes hashes SHA-1 porque se basan en un origin/feature
diferente del que los ha cambiado en su repositorio local.
Aquí hay un ejemplo. Supongamos que esta es tu historia antes de hacer git pull
en master
:
A - B - C (master)
/
D - E (feature)
Después de git pull
, el master
consiguió cometer F
:
A - B - C - F (master, origin/master)
/
D - E (feature)
En ese punto, se vuelve a generar la feature
en la parte superior del master
, que aplica D
y E
:
A - B - C - F (master, origin/master)
/
D - E (feature)
Mientras tanto, el origin/feature
rama remota aún se basa en la confirmación C
:
A - B - C - F (master, origin/master)
/ /
/ D'' - E'' (feature)
/
D - E (origin/feature)
Si realiza un git status
en la feature
, Git le dirá que su rama de la feature
se ha desviado del origin/feature
con 3 ( F
, D''
, E''
) y 2 ( D
, E
) confirmaciones, respectivamente.
Tenga en cuenta que
D''
yE''
contienen los mismos cambios queD
yE
pero tienen diferentes ID de confirmación porque se han vuelto a basar sobreF
La solución es hacer git pull
en el master
y la feature
antes de rebasar la feature
en el master
. Sin embargo, como es posible que tenga confirmaciones en la feature
que aún no ha introducido en el origin
, desearía hacerlo:
git checkout feature && git pull --rebase
para evitar crear una confirmación de fusión entre origin/feature
y su feature
local.
Actualización sobre las consecuencias de rebasar:
A la luz de este comentario , amplié las ramas divergentes. La razón por la que git status
informa que la feature
y el origin/feature
divergen después de la reorganización se debe al hecho de que el reabastecimiento trae nuevos compromisos a la feature
, además de que reescribe los confirmaciones que se enviaron previamente al origin/feature
.
Considere la situación después del tirón pero antes de la rebase:
A - B - C - F (master)
/
D - E (feature, origin/feature)
En este punto, la feature
y el origin/feature
apuntan a la misma confirmación E
en otras palabras, están en " sincronización ". Después de rebasar la feature
en la parte superior del master
, el historial se verá así:
A - B - C - F (master)
/ /
/ D'' - E'' (feature)
/
D - E (origin/feature)
Como puede ver, la feature
y el origin/feature
han divergido , su ancestro común está comprometido con C
Esto se debe a que la feature
ahora contiene la nueva confirmación F
del master
más D''
y E''
(leída como " D prime " y " E prime "), que son las confirmaciones D
y E
aplicadas sobre F
A pesar de que contienen los mismos cambios, Git los considera diferentes porque tienen diferentes ID de confirmación. Mientras tanto, el origin/feature
aún hace referencia a D
y E
En este punto, ha reescrito la historia : ha modificado las confirmaciones existentes en virtud de volver a basarlas, creando efectivamente "nuevas".
Ahora, si tuviera que ejecutar la función git pull
on esto es lo que sucedería:
A - B - C - F (master)
/ /
/ D'' - E''- M (feature)
/ /
D - E - (origin/feature)
Dado que git pull
hace git fetch
+ git merge
, esto resultaría en la creación del merge commit M
, cuyos padres son E''
y E
Si, en cambio, ejecutó git pull --rebase
(es decir, git fetch
+ git rebase
), entonces Git:
- Mover
feature
para confirmarC
(el antecesor común defeature
yorigin/feature
) - Aplicar
D
yE
desdeorigin/feature
- Aplicar
F
,D''
yE''
Sin embargo, al darse cuenta de que D''
y E''
contienen los mismos cambios que D
y E
, Git simplemente los descartaría, lo que resultaría en una historia como esta:
A - B - C - F (master)
/
D - E - F'' (feature)
^
(origin/feature)
Observe cómo el commit F
, que antes era accesible desde la feature
, se aplicó en la parte superior del origin/feature
resultó en F''
. En este punto, el git status
te diría esto:
Su sucursal está por delante de ''origen / característica'' por 1 confirmación.
Que se comprometan siendo, por supuesto, F''
.