¿Por qué ocurre un conflicto solo para una confirmación en lugar de dos en mi operación de rebase?

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:

  1. cuando se aplique el primer commit desde rep2 y las líneas line1-modified-rep1 vs line1-modified-rep2 pondrán en conflicto
  2. cuando se aplicará la primera confirmación desde 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: enter image description here

enter image description here

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 

TL; DR

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.

Más detalles

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):

enter image description here

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:

enter image description here

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" 

enter image description here

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

enter image description here

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.