Tengo rep1
repository rep1
con dos confirmaciones en la twig master
. Estos commits tienen file.txt
con el siguiente contenido:
line1 line2
rep1
en rep2
y rep2
la twig remota como seguimiento:
git checkout --track rep1/master
Luego, en este repository, modifico la primera línea de file.txt
para que sea:
line1-modified-rep2 line2
Hacer commit. Luego modifica su segunda línea para ser
line1-modified-rep2 line2-modified-rep2
Hacer commit. Entonces, aquí en el rep2
he agregado dos commits a la twig master
que rastrea la twig rep1/master
remota.
Ahora voy a generar un conflicto. En el repository de rep1
remoto, creo el tercer commit (ya hay dos) modificando file.txt
en la primera y segunda línea para ser:
line1-modified-rep1 line2-modified-rep1
Ok, ahora estamos listos para el conflicto de fusión. rep2
confirmaciones de rep2
a rep1
, me rechazan y cuando se solicita una rebase
select esta opción.
Ahora, estaba leyendo que rebase
aplicaría mis dos commits desde rep2
(donde modifiqué dos líneas con prefix -rep2
) sobre el tercer commit sincronizado desde rep1
(con líneas modificadas con prefix -rep1
) y entonces estoy esperando dos conflictos de fusión:
rep2
y las líneas line1-modified-rep1 vs line1-modified-rep2
pondrán en conflicto rep2
y las líneas line2-modified-rep1 vs line2-modified-rep2
entrarán en conflicto Pero solo hay un conflicto de fusión y en su resolución puedo impulsar mis compromisos con éxito a la rep1
. ¿Que me estoy perdiendo aqui?
PD. Perdón por la larga elaboración, traté de presentar mi caso lo más claro posible.
EDITAR:
Entonces la configuration antes de rebase es la siguiente:
A--D (rep1) \ B--C (rep2)
Capturas de pantalla agregadas del process de resolución:
Entonces, el file resultante después de la resolución del conflicto contiene estas líneas:
line1-modified-rep2 line2
Este es un logging de commands git grabados por phpstorm (el origen es rep1
aquí):
23:19:49.586: git -c core.quotepath=false fetch origin --progress --prune remote: Counting objects: 5, done.[K remote: Total 3 (delta 0), reused 0 (delta 0)[K From E:/rep1 acc72ac..e6317e8 master -> origin/master 23:20:39.118: cd E:\rep2 23:20:39.118: git -c core.quotepath=false rebase origin/master First, rewinding head to replay your work on top of it... Applying: rep2-commit 2 Using index info to reconstruct a base tree... M file.txt Falling back to patching base and 3-way merge... Auto-merging file.txt CONFLICT (content): Merge conflict in file.txt Failed to merge in the changes. Patch failed at 0001 rep2-commit 2 The copy of the patch that failed is found in: e:/rep2/.git/rebase-apply/patch When you have resolved this problem, run "git rebase --continue". If you prefer to skip this patch, run "git rebase --skip" instead. To check out the original branch and stop rebasing, run "git rebase --abort". 23:24:33.418: cd E:\rep2 23:24:33.418: git -c core.quotepath=false add --ignore-errors -- file.txt 23:24:33.630: cd E:\rep2 23:24:33.630: git -c core.quotepath=false rebase --continue Applying: rep2-commit 2 Applying: rep2-commit 3
Solo se produce un conflicto al comienzo de la operación de rebase. Debido a la forma en que resuelve ese conflicto, el segundo parche se aplica limpiamente; no hay causa para conflictos adicionales.
Para completar, aquí está cómo recrear una versión simplificada de su ejemplo de juguete desde la línea de command; He acortado las líneas en file.txt
un poco, para mayor comodidad:
mkdir rep1 cd rep1 git init printf "l1\nl2\n" > file.txt git add touch.txt git commit -m "initial commit" cd .. git clone rep1 rep2 git remote rename origin rep1 # for clarity cd rep2 sed -i '.txt' 's/l1/l1rep2/' file.txt git commit -am "append 'rep2' to first line" sed -i '.txt' 's/l2/l2rep2/' file.txt git commit -am "append 'rep2' to second line" cd ../rep1 sed -i '.txt' 's/$/rep1/' file.txt git commit -am "append 'rep1' to both lines" cd ../rep2 git fetch
Después de todos esos commands, su repo rep2
ve de la siguiente manera (el contenido de file.txt
se muestra debajo de cada confirmación):
Ahora, en rep2
, corres
git rebase rep1/master
Para comprender lo que sucede durante esta rebase, recuerde que una rebase es poco más que una serie de operaciones de selección de cereza, seguidas de algunas reorganizaciones de twigs; esto está bien explicado en el tutorial Think as a Git .
Primero, Git intenta reproducir el "parche A
-> B
" sobre el compromiso D
Sin embargo, Git no puede aplicar este parche limpiamente; En términos generales, Git, por sí solo, no tiene forma de averiguar qué versiones de las dos líneas se supone que debe mantener:
Sin saber qué hacer, Git le pide que resuelva el conflicto, lo que hace reemplazando el contenido de file.txt
por
l1-rep2 l2
(lo cual es polémico, porque eso crea una fusión maligna , como señala Daniel Böhmer en su comentario ). Luego escenificas y comprometes los cambios:
git commit -am "conflict resolution"
Ahora ejecuta git rebase --continue
, y Git luego intenta reproducir el parche " B
-> C
" encima de confirmar E
… ¡y tiene éxito ! Ese parche se aplica limpiamente; Debido a que los contenidos de file.txt
en commits B
y E
son idénticos, no hay motivo para ningún conflicto aquí, y terminas con
Al mirar tus capturas de pantalla, no obtuviste el conflicto en tu segunda confirmación aplicada. Verifique los cambios-> Registro de su PhpStorm y verá dos confirmaciones en la parte superior del remote/master
. O tal vez incluso tres, a juzgar por la salida de su git
Applying: rep2-commit 2 Applying: rep2-commit 3
Editar
La razón por la que no se generó conflicto por segunda vez es porque la fusionó para que el file esté exactamente en el estado de rep2-commit 2
. Si elige realizar cambios en rep1, tendría conflictos mucho más allá.
Mis dos centavos. Justo antes de iniciar la rebase, tenías algo así como:
A--B--C--D--E rep2
\
F rep1
Después de la rebase, obtienes
A--B--C
\
F--D'--E' rep2
¿Derecha?
De la documentation de git rebase , entiendo que el contenido de commits D y E se guarda primero en un área temporal. Commit D se aplica por primera vez además del compromiso F, generando un conflicto. Al final de la resolución del conflicto, se crea el compromiso D '. Luego, se aplica el compromiso E sobre el compromiso D '. Commit E es la modificación de la línea 2 en file.txt después del commit D. Entonces mi punto es: resolución de conflictos para generar D 'es el paso crítico. En function de la elección realizada, el file de contenido.txt para la confirmación D 'es igual al contenido de file.txt en la confirmación D. En ese caso, no habría ningún conflicto al tratar de generar E' además de la confirmación D.