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

90

Utilizo git-svn y noté que cuando tengo que arreglar un conflicto de fusión después de realizar una git svn rebase, el significado de las opciones --oursy --theirspara, por ejemplo, git checkoutse invierte. Es decir, si hay un conflicto y quiero mantener la versión que vino del servidor SVN y deshacerme de los cambios que hice localmente, tengo que usar ours, cuando espero que sea 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"
Marc Liyanage
fuente
Jut actualizó mi respuesta con muchos diagramas para ilustrar mejor los lados "nuestro" y "suyo".
VonC
1
Véase también github.com/git/git/commit/…
VonC

Respuestas:

230

Eso parece coherente con lo que hace una rebase.

  • git svn rebase obtendrá las revisiones del padre SVN del HEAD actual y volverá a basar el trabajo actual (no comprometido con SVN) en su contra.

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

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

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

Si concilia ambas definiciones:

  • las confirmaciones provenientes de SVN son aquellas además de las cuales se reproducen las confirmaciones locales de Git. Son parte de la "serie modificada hasta ahora" y se denominan "nuestro" (en su caso, el test.txtarchivo con barcontenido).
  • la rama de trabajo (que contiene confirmaciones de Git desconocidas para SVN, en su caso, el test.txtarchivo con bazcontenido) es "su", y cada una de esas confirmaciones de Git locales se está reproduciendo.

En otras palabras, SVN o no:

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

Buen consejo mnemónico de CommaToast :

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

(y la primera cosa que una git rebase upstreamlo hace para obtener de la upstreamrama sobre la que desea reajustar: CABEZA refiere a upstream- oursahora).


Es probable que la confusión provenga del papel de la rama trabajadora en un clásico git merge.
Cuando se fusiona:

  • la "rama de trabajo" es la que contiene lo que está "hasta ahora fusionado", y se considera como "nuestro",
  • mientras que la otra confirmación representa lo que se está reproduciendo, no reproduciéndose, sino que se fusiona en la parte superior de la rama de trabajo y se considera como "su".

Como git rebasemenciona la página de manual, una combinación durante un rebase significa que se intercambian los lados.


Otra forma de decir lo mismo es considerar que:

  • lo que tenemos en la rama comprobada es ' nuestro ',
  • lo que teníamos (y se está fusionando o reproduciendo) es "de ellos ".

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', así que lo que tenemos sigue siendo en lo que estábamos trabajando (y nos fusionamos desde 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 las confirmaciones actuales encima)

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

A git rebase upstreamprimero cambiará HEADde B a la rama ascendente HEAD(de ahí el cambio de 'nuestro' y 'suyo' 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 rama B de 'nuestra':

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 git svn rebasees que se realiza primero una "búsqueda" de svn en la rama remota de Git que representa las confirmaciones de SVN.
Inicialmente tienes:

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 nuevas confirmaciones 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 las confirmaciones en las que estabas trabajando (pero que ahora son "suyas" durante ese 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
VonC
fuente
9
Vaya, que gran respuesta, gracias! Debo haber perdido por completo ese comentario en la git rebasepágina de manual ...
Marc Liyanage
@epologee: de nada. También es útil cuando está usando solo git, para comprender lo que está sucediendo durante una rebase frente a una fusión. Y se suma a la definición ascendente: stackoverflow.com/questions/2739376/…
VonC
5
¡¡¡Dios mío!!! ¿Qué tipo de drogas estaba tomando Torvalds? ¡Esto es demasiado complicado! Git es una herramienta muy peligrosa. Puede destruir fácilmente todo su trabajo si intenta utilizar el conocimiento externo o su intuición. ¡El desarrollo de software se ha ido al garete!
ATL_DEV
@ user148298 No hay nada malo en esta función. No tienes que saber todo ese tipo de cosas a menos que seas un experto en git. Y si necesita funciones avanzadas, primero tendrá que aprenderlas.
Earth Engine