git rebase -i -autosquash conflict

git me causa un gran dolor de cabeza cuando uso —fixup y –autosquash. Me gustaría dar dos ejemplos, uno funciona perfectamente bien y el otro es un desastre. (git versión 2.6.2)

Ejemplo de trabajo:

Primer compromiso:

$ git init $ printf '1\n' > test.file $ git add test.file $ git commit -m 'Insert 1 --> first line' $ cat test.file 1 

Segundo commit (ERROR):

 $ printf 'This is\na BUG\n' >> test.file $ git commit -am 'Added line 2 and 3 with BUG' $ cat test.file 1 This is a BUG 

Tercer compromiso:

 $ sed -i '2i 2' test.file $ git commit -am 'Insert 2 --> second line' $ cat test.file 1 2 This is a BUG 

Cuarto compromiso (corrección):

 $ sed -i 's/a BUG/NOT a BUG/' test.file $ git add test.file $ git log --oneline b021696 Insert 2 --> second line 2e18b8d Added line 2 and 3 with BUG d7b60a1 Insert 1 --> first line $ git commit --fixup HEAD~ $ cat test.file 1 2 This is NOT a BUG 

Rebase:

 $ git log --oneline fe99989 fixup! Added line 2 and 3 with BUG b021696 Insert 2 --> second line 2e18b8d Added line 2 and 3 with BUG d7b60a1 Insert 1 --> first line $ git rebase -i --autosquash HEAD~3 [detached HEAD 6660b0e] Added line 2 and 3 with BUG Date: Tue Nov 3 13:28:07 2015 +0100 1 file changed, 2 insertions(+) Successfully rebased and updated refs/heads/master. 

Ejemplo de dolor de cabeza: (La única diferencia es que el compromiso BUGGY es una sola línea)

Primer compromiso:

 $ git init $ printf '1\n' > test.file $ git add test.file $ git commit -m 'Insert 1 --> first line' $ cat test.file 1 

Segundo commit (ERROR):

 $ printf 'This is a BUG\n' >> test.file $ git commit -am 'Added line 2 with BUG' $ cat test.file 1 This is a BUG 

Tercer compromiso:

 $ sed -i '2i 2' test.file $ git commit -am 'Insert 2 --> second line' $ cat test.file 1 2 This is a BUG 

Cuarto compromiso (corrección):

 $ sed -i 's/a BUG/NOT a BUG/' test.file $ git add test.file $ git log --oneline 2b83fe7 Insert 2 --> second line 62cdd05 Added line 2 with BUG 0ee3343 Insert 1 --> first line $ git commit --fixup HEAD~ $ cat test.file 1 2 This is NOT a BUG 

Rebase:

 $ git log --oneline c3d3db7 fixup! Added line 2 with BUG 2b83fe7 Insert 2 --> second line 62cdd05 Added line 2 with BUG 0ee3343 Insert 1 --> first line $ git rebase -i --autosquash HEAD~3 error: could not apply c3d3db7... fixup! Added line 2 with BUG 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". Could not apply c3d3db78440e48c1bb637f78e0767520db65ea1e... fixup! Added line 2 with BUG $ git status interactive rebase in progress; onto 0ee3343 Last commands done (2 commands done): pick 62cdd05 Added line 2 with BUG fixup c3d3db7 fixup! Added line 2 with BUG Next command to do (1 remaining command): pick 2b83fe7 Insert 2 --> second line (use "git rebase --edit-todo" to view and edit) You are currently rebasing branch 'master' on '0ee3343'. (fix conflicts and then run "git rebase --continue") (use "git rebase --skip" to skip this patch) (use "git rebase --abort" to check out the original branch) Unmerged paths: (use "git reset HEAD <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: test.file no changes added to commit (use "git add" and/or "git commit -a") $ cat test.file 1 <<<<<<< HEAD This is a BUG ======= 2 This is NOT a BUG >>>>>>> c3d3db7... fixup! Added line 2 with BUG 

¿Por qué la corrección no se aplica limpiamente?

¿Por qué la corrección también contiene "2", que no debería estar en el parche introducido por la corrección pero en el parche de la confirmación anterior.

Cuando haces una – --fixup , estás aplicando un parche fuera de service, por lo que el context ha desaparecido. En el primer caso, sus parches se aplican de la siguiente manera:

  1. Insertar 1 en la línea 1
  2. Insertar This is\naBUG en las líneas 2, 3 después de 1
  3. Eliminar la línea a BUG , en la línea 4, después de This is , replace con NOT a BUG
  4. Inserta 2 en la línea 2 después de 1 , antes This is

Los pasos 2 y 3 son bastante claros. Aunque el número de línea es diferente de lo esperado en el paso 3, el context lo deja en claro. En el segundo caso,

  1. Insertar 1 en la línea 1
  2. Insertar This is a BUG en la línea 2 después de 1
  3. Eliminar línea This is a BUG , replace con This is NOT a BUG en la línea 3 después de la línea 2
  4. Inserta 2 en la línea 2, después de 1 , antes This is a BUG

En este caso, el parche # 3 es imposible porque This is a BUG no aparece en la línea 3 y la línea antes no es 2 . Git no supone que la línea 2 sea la correcta en este caso debido al context faltante.

La forma más fácil de solucionar este problema es reorganizar el order de la rebase para reflejar lo que realmente está haciendo. En lugar de la order original:

 pick 5ef0459 Added line 2 with BUG fixup ed5cd81 fixup! Added line 2 with BUG pick 20e104e Insert 2 --> second line 

cambie los dos últimos elementos para darle al parche el context que necesita:

 pick 5ef0459 Added line 2 with BUG pick 20e104e Insert 2 --> second line fixup ed5cd81 fixup! Added line 2 with BUG 

En este caso, puede que necesite agregar el -k a su línea de command para conservar el último compromiso, que básicamente está vacío:

 $ git rebase -i -k --autosquash HEAD~3 Date: Tue Nov 3 10:45:40 2015 -0500 1 file changed, 2 insertions(+), 1 deletion(-) Successfully rebased and updated refs/heads/master. $ cat test 1 2 This is NOT a BUG 

La otra alternativa es, por supuesto, arreglar el conflicto manualmente usando git merge o git mergetool , siguiendo las instrucciones cuando falla la rebase.

Puede hacer que la rebase tenga "éxito" agregando -s recursive -X theirs o -s recursive -X ours para especificar la estrategia. Sin embargo, debido al conflicto de context, su corrección será eliminada en ambos casos.

Creo que el problema es el context de los cambios. Mira este compromiso:

 $ git show c3d3db7 diff --git a/test.file b/test.file index 7a103db..8c8e69a 100644 --- a/test.file +++ b/test.file @@ -1,3 +1,3 @@ 1 2 -This is a BUG +This is NOT a BUG 

Y desea aplicar este parche al file con los contenidos:

 1 This is a BUG 

¿Ver? El parche no se aplica, porque el context no coincide. Entonces surge un conflicto y tienes que arreglarlo manualmente.


Cuando tienes la línea del insecto dividida en dos, el parche es algo así como:

 diff --git a/test.file b/test.file --- a/test.file +++ b/test.file @@ -1,3 +1,3 @@ 1 2 This is -a BUG +NOT a BUG 

Y el file es:

 1 This is a BUG 

Ahora, aunque la coincidencia no es perfecta, al less la primera línea sin modificar del context coincide, por lo que la fusión puede continuar.