Git cherry-pick causa conflicto de fusión mientras fusión no

Estoy tratando de aprender a usar git cherry pick, leí las páginas de manual que git devuelve haciendo git cherry-pick --help pero eso no pareció ayudar. Voy a tratar de explicar el problema a continuación. Tengo dos twigs master y other .

En la twig master El historial de confirmación es

 0x2 Second commit from master branch 0x1 Initial commit 

Y el único file en el repository que estoy rastreando readme tiene los siguientes contenidos

 Some text 

En la twig other El historial de commit es

 0x5 CHECKPOINT, going to cherry-pick onto master 0x4 second commit from branch other 0x3 first commit from other branch: 0x2 Second commit from master branch 0x1 Initial commit 

Y el contenido del file readme es

 Some text. Adding some text from other branch. Adding some more text. Going to cherry-pick this commit. 

El directory de trabajo está limpio en ambas twigs sin cambios sin seguimiento. A partir de este momento, cuando cambio a la twig principal y me fusiono con git merge other la fusión se realiza sin conflictos de fusión. Pero cuando pruebo git cherry-pick 0x5 hay un conflicto de fusión, obtengo la siguiente salida de git

 error: could not apply 0x5... CHECKPOINT, going to cherry-pick onto master hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit' 

Y el file readme tiene los siguientes contenidos

 <<<<<<< HEAD Some text ======= Some text. Adding some text from other branch. Adding some more text. Going to cherry-pick this commit. >>>>>>> 0x5... CHECKPOINT, going to cherry-pick onto master 

¿Por qué hay este conflicto de fusión? Estoy tratando de entender por qué ocurre. ¿No debería ser igual que tratar de hacer todas las ediciones hechas en el compromiso que debe ser cherry-pick ti mismo y luego comprometer ese cambio en la twig ( master en este caso)?

Además, cuando exactamente hay un conflicto de fusión en git ? Parece que los tengo en momentos extraños. ¿Es dependiente de esta implementación (por ejemplo, depende del algorithm utilizado para fusionarse)?

¡Gracias!

Solutions Collecting From Web of "Git cherry-pick causa conflicto de fusión mientras fusión no"

Acabo de probar ese escenario, después de leer:

  • " ¿Por qué Cherry-Pick siempre resulta en un conflicto de fusión? "
  • " Desmitificando a Git: 3 conceptos para hacer todo con Git "

Si la modificación de la primera línea ( Some text. lugar de Some text ) se realizó inmediatamente después de 0x2, como en 0x3, entonces git cherry-pick 0x3 funciona sin conflicto.

Pero si ese mismo cambio se realiza unos commits más tarde, el git cherry-pick no generará un parche compatible con el contenido de 0x2.

No hay ninguna noción de "antepasado común" aquí ( como se indica incorrectamente aquí ): solo de "parche".

Un git cherry-pick , incluso si usa estrategias de fusión, no es una git merge .

  • Una git merge searchá un ancestro común (retrocediendo en el historial de confirmaciones de 0x5, para encontrar una confirmación común con 0x2: aquí mismo 0x2)
  • Un git cherry-pick solo crea un parche al hacer una diferencia unificada entre dos commits (por defecto, el commit que mencionas y su padre inmediato 0x4)

El punto es que ese parche no se podrá aplicar encima de 0x2.

Prueba si es para ti: un git cherry-pick 0x5 es como hacer un git diff -p 0x4..0x5 .
Verá en esas líneas de parche que no son parte de 0x2, y refleja los cambios que vienen de 0x3 o 0x4.

Tal parche no se puede aplicar en 0x2, ya que se basa en un contenido que no existe para 0x2.

He creado un informe de testing en el que hice desde el maestro dos modificaciones.

  • Agregar text de otra twig (sin modificación a la primera línea)
  • Luego, un segundo compromiso modificará la primera línea.

Aquí cómo se ve mi parche:

 C:\Users\vonc\prog\git\tests\cp>git diff -p dev~..dev diff --git a/fb/f index 2b6dd7b..1c4bb79 100644 --- a/f +++ b/f @@ -1,4 +1,4 @@ -"Some text" +"Some text."^M Adding some text from other branch. Adding some more text. 

No puedo aplicar (cherry-pick) a cometer en 0x2, ya que 0x2 no tiene línea " Adding some text from other branch " todavía. Solo tiene una línea "Some text" .

Es por eso que git informa un conflicto: el contenido ha divergido, y ese parche se supone que debe cambiar la línea 1 en la parte superior de un file que incluye " Adding some text from other branch ", que 0x2 no tiene.

Esto difiere de una git merge de git merge por supuesto, ya que una fusión de git searchá un ancestro común (aquí 0x2) e informa todas las modificaciones desde 0x2 en 0x2 sin ningún problema.

Si dices merge , se merge las tres (3-5) confirmaciones. Si cherry-pick solo el último, se usa. El file (s) que concierne puede tener cambios ya en 3 y / o 4 por lo que la etapa inicial no coincide con lo esperado.

Verifique el conflicto para ver por qué sucede con una herramienta de combinación.

Por ejemplo, esto causará un conflicto:

 Original Original Original Commit3 Original Commit5 Original 

Aquí el motor de diferencia de git mostrará que cambiaste una línea que está precedida por unas pocas líneas, incluida una línea del commit 3. Cherry-picking no ve esa línea en el original así que git gritará conflicto y te pedirá que lo manejes. No hay edición conflictiva per se (por ejemplo, se editó la misma línea), git simplemente no está seguro de dónde colocar la parte editada.

Por supuesto, puede editar manualmente los files como quiera. Solo fusionar sucursales tendrá problemas y conflictos, y no todos los conflictos significan que "no puedes hacer esto", solo significan "No sé exactamente qué hacer, tú mismo lo resuelves".

Hagamos un pequeño experimento de su caso.

 mkdir tmp cd tmp git init echo "root" >> hello git add hello git commit -m 'root commit' git branch exp #open the file hello and write 111 in the 2nd line git add hello git commit -m '111' #open the file hello and modify 111 to 112 in the 2nd line git add hello git commit -m '222' #now we have 3 commits in the master branch git log --oneline 6b86a6d 112 663a36b 111 28b2e12 root commit git checkout exp #now we are in the exp branch, which has only 1 root commit. git log --oneline 28b2e12 root commit #now we try to cherry pick 6b86a6d git cherry-pick 6b86ad6 error: could not apply 6b86a6d... 112 hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit' #a conflict occurs,why? 

El segundo compromiso en la twig maestra es igual a modify the 2nd line, from empty to 111 El 3.º compromiso en la twig principal es igual a la modify the 2nd line, from 111 to 112

Podemos ver que el 3º depende del 2º. Si no hubiera 111, no podríamos actualizar 111 a 112. Cuando seleccionamos cuidadosamente el 3º sin el 2º, no se encuentra el 111 en el file hola de la twig exp, lo que llevó al conflicto.

Si seleccionamos cuidadosamente el 2º primero, la segunda línea de hola se actualizará de vacía a 111. Y luego, si seleccionamos el 3º, la segunda línea de hola se actualizará de 111 a 112.

Sigamos con el experimento.

 #abor the cherry-pick first git cherry-pick --abort #go back to the master branch git checkout master > world git add world git commit -m 'add new file world' git log --oneline 1cf8f90 add new file world 6b86a6d 112 663a36b 111 28b2e12 root commit #now we have 4 commits in the master branch #cherry pick the 4th commit into the exp branch git checkout exp git cherry-pick 1cf8f90 [exp 79a34bb] add new file world Date: Sun May 15 20:55:39 2016 +0800 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 world #no error 

El cuarto commit es igual a add a new file world . Este cambio no depende del segundo o tercer commit. Puede ser seleccionado en la twig exp sin ningún problema.

Volvamos al escenario de conflicto.

 #cherry pick the 3rd commit again git cherry-pick 6b86a6d error: could not apply 6b86a6d... 112 hint: after resolving the conflicts, mark the corrected paths hint: with 'git add <paths>' or 'git rm <paths>' hint: and commit the result with 'git commit' git status On branch exp You are currently cherry-picking commit 6b86a6d. (fix conflicts and run "git cherry-pick --continue") (use "git cherry-pick --abort" to cancel the cherry-pick operation) Unmerged paths: (use "git add <file>..." to mark resolution) both modified: hello #we can see conflict ocurrs in the file hello. open hello with text editor hello world <<<<<<< HEAD ======= 112 >>>>>>> 6b86a6d... 112 

<<< y >>> parte es el context de conflicto. La parte <<< y === es lo que es ahora en la twig actual, también conocida como la twig exp. Está en blanco. === y >>> parte es lo que está en la confirmación 6b86a6d. Es 112. El process de selección selectiva no puede decidir qué parte aplicar, por lo que tenemos que hacerlo por nosotros mismos. Si insistimos en que debe estar en blanco, simplemente elimine las líneas de <<<, ===, >>> y 112. Si queremos 112 en su lugar, simplemente elimine las líneas de <<<, ===,> >>. Por supuesto, podemos mantener todos excepto <<<, === y >>> en algún caso. En una palabra, conserve lo que quiere y elimine lo que no necesita. Guardar y Salir. git add hello;git cherry-pick --continue Entonces todo está hecho. Para get más información, consulte "CÓMO SE PRESENTAN LOS CONFLICTOS" en git merge --help .

En otro caso, si dos commits de dos twigs actualizan la misma línea o líneas con diferentes contenidos y git cherry-pick one commit a la otra twig, también genera conflicto.

Voy a ser less técnico y más "sentido común" que las otras respuestas. (Lo cual no siempre es lo correcto, pero creo que es en este caso).

Usted está pensando: "Es obvio, el cambio que quiero simplemente agrega una línea al final del file. ¿Por qué no solo hace eso?"

Git está aplicando un parche. La aplicación de un parche implica tratar de descubrir dónde debe ir el parche. Esto implica mirar el número de línea aproximado y search n líneas de context idéntico antes y después de realizar el cambio. En este caso, el context posterior es Fin del file. Pero el context anterior "Agregar text de otra twig. Agregar más text". no se puede encontrar en el file de destino. Por lo tanto, Git señala esto como "No puedo hacer coincidir el context antes y el después de este cambio, así que colocaré marcadores de conflicto donde probablemente debería ir el cambio, pero dejo a la inteligencia humana la resolución final".

Si bien en este caso usted sabe que esto podría haber sido resuelto trivialmente, hay muchos casos similares en los que los codificadores han estado muy contentos de que git haya marcado una situación como esta y les permita solucionarla manualmente.

Si esto es algo que te encontrarás a menudo, git te permite escribir manejadores de combinación personalizados para los files, así que si sabes más sobre los patrones de fusión esperados y permitidos y la syntax de tus files, puedes codificarlos en un controller de combinación.