with tortoise migrar branches git git-svn

tortoise - ¿Por qué se invierte el significado de "nuestro" y "de ellos" con git-svn?



migrate svn to git with branches (1)

Yo uso git-svn y noté que cuando tengo que arreglar un conflicto de fusión después de realizar una git svn rebase , el sentido de la --ours y --theirs opciones para, por ejemplo, git checkout se invierte. Es decir, si hay un conflicto y quiero conservar la versión que proviene del servidor SVN y deshacerme de los cambios que hice localmente, tengo que usar los ours , cuando esperaría que fueran los theirs .

¿Porqué es eso?

Ejemplo:

mkdir test cd test svnadmin create svnrepo svn co file://$PWD/svnrepo svnwc cd svnwc echo foo > test.txt svn add test.txt svn ci -m ''svn commit 1'' cd .. git svn clone file://$PWD/svnrepo gitwc cd svnwc echo bar > test.txt svn ci -m ''svn commit 2'' cd .. cd gitwc echo baz > test.txt git commit -a -m ''git commit 1'' git svn rebase git checkout --ours test.txt cat test.txt # shows "bar" but I expect "baz" git checkout --theirs test.txt cat test.txt # shows "baz" but I expect "bar"


Eso parece consistente con lo que hace una rebase.

  • git svn rebase obtendrá revisiones del padre SVN del HEAD actual y rebases el trabajo actual (no confirmado a SVN) en su contra.

  • git rebase menciona:
    Tenga en cuenta que una fusión de rebase funciona al repetir cada confirmación desde la rama de trabajo en la parte superior de la rama <upstream> .
    Debido a esto, cuando ocurre un conflicto de fusión:

    • el lado reportado como el nuestro es la serie hasta ahora rebasada, comenzando con <upstream> ,
    • y la suya es la rama de trabajo .
      En otras palabras, los lados se intercambian .

git rebase reproduce cada confirmación desde la rama de trabajo en la parte superior de la rama <upstream> .

Si reconcilia ambas definiciones:

  • los commits provenientes de SVN son aquellos sobre los cuales se reproducen las confirmaciones locales de Git. Son parte de la "serie rebasada hasta ahora", y se mencionan como "nuestro" (en su caso, el archivo test.txt con contenido de bar )
  • la rama de trabajo (que contiene Git commits unknown to SVN, en su caso, el archivo test.txt con contenido baz ) es "their", y cada una de esas confirmaciones locales de Git se están reproduciendo.

En otras palabras, SVN o no:

  • la rama " <upstream> " (en la parte superior de la cual se reproduce cualquier cosa, y que es parte de las confirmaciones rebasadas hasta ahora) es " nuestra ".
  • lo que se está reproduciendo (la rama de trabajo) es "de ellos ".

Buena punta mnemotécnica de CommaToast :

lo que sea que HEAD señale es "nuestro"

(y lo primero que hace un git rebase upstream es realizar la git rebase upstream la rama upstream encima de la cual desea volver a establecer la base: HEAD se refiere a la cadena upstream : la ours ahora).

La confusión probablemente proviene del rol de la rama de trabajo en una git merge clásica.
Cuando te estás fusionando:

  • la "rama de trabajo" es la que contiene lo que está "hasta ahora fusionada", y se considera como "nuestro",
  • mientras que el otro compromiso representa lo que está siendo reproducido, pero no se reproduce, en la parte superior de la rama de trabajo, y considerado como "su".

Como menciona la página de git rebase , una combinación durante una rebase significa que el lado se intercambia.

Otra forma de decir lo mismo es considerar que:

  • lo que tenemos en la rama de salida es '' nuestro '',
  • lo que teníamos (y está siendo fusionado o repetido) es '' suyo ''.

En una fusión :

x--x--x--x--x(*) <- current branch B (''*''=HEAD) / / /--y--y--y <- other branch to merge

, no cambiamos la rama actual ''B'', entonces lo que tenemos es aún en lo que estábamos trabajando (y nos fusionamos de otra rama)

x--x--x--x--x---------o(*) MERGE, still on branch B / ^ / / ours / / / --y--y--y--/ ^ their

¡Pero en una rebase , cambiamos de lado porque lo primero que hace una rebase es verificar la rama ascendente! (para reproducir los commits actuales en la parte superior)

x--x--x--x--x(*) <- current branch B / / /--y--y--y <- upstream branch

Un git rebase upstream cambiará primero HEAD of B a HEAD de la rama upstream (de ahí el cambio de ''ours'' y ''theirs'' en comparación con la rama de trabajo "actual" anterior).

x--x--x--x--x <- former "current" branch, new "theirs" / / /--y--y--y(*) <- upstream branch with B reset on it, new "ours", to replay x''s on it

, y luego la rebase reproducirá ''sus'' confirmaciones en la nueva ''nuestra'' rama B:

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs / / /--y--y--y--x''--x''--x''(*) <- branch B with HEAD updated ("ours") ^ | upstream branch

El único paso adicional con git svn rebase es que git svn rebase se realiza una "búsqueda" de svn en la rama remota de Git que representa las confirmaciones de SVN.
Tienes inicialmente:

x--x--x--x--x(*) <- current branch B, "ours" for now. / / /--y--y--y <- SVN tracking branch, "theirs for now"

, primero actualiza la rama de seguimiento de SVN con nuevos commits provenientes de SVN

x--x--x--x--x(*) <- current branch B, still "ours", not for long / / /--y--y--y--y''--y'' <- SVN tracking branch updated

, luego cambia la rama actual al lado SVN (que se convierte en "nuestro")

x--x--x--x--x <- for "B", now "their" during the rebase / / /--y--y--y--y''--y''(*) <- SVN tracking branch updated, and branch B: now "ours" (this is "what we now have")

, antes de reproducir los commits en los que estabas trabajando (pero que ahora son "suyos" durante esa rebase)

x--x..x..x..x <- old "theirs" commits, now "ghosts", available through reflogs / / /--y--y--y--y''--y''--x''--x''--x''(*) <- branch B with HEAD updated ("ours") ^ | upstream SVN tracking branch