2010-06-02 9 views
84

Używam git-svn i zauważyłem, że kiedy muszę naprawić konflikt scalania po wykonaniu git svn rebase, znaczenie opcji --ours i --theirs na przykład git checkout jest odwrotny. Oznacza to, że jeśli wystąpi konflikt i chcę zachować wersję, która pochodzi z serwera SVN i wyrzucić zmiany, które wprowadziłem lokalnie, muszę użyć ours, kiedy spodziewam się, że będzie to theirs.Dlaczego znaczenie "nasz" i "ich" odwrócono git-svn

Dlaczego tak jest?

Przykład:

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" 
+0

Jut zaktualizowałem moją odpowiedź wieloma diagramami, aby lepiej zilustrować strony "nasze" i "ich". – VonC

+1

Zobacz także https://github.com/git/git/commit/f30301657b68561392d910f6196380dd3976549e – VonC

Odpowiedz

211

To wydaje się zgodny z tym, co robi rebase.

  • git svn rebase wola pobiera wersje z SVN rodzica obecnego szefa i rebases obecny (niezatwierdzone do SVN) działają przeciwko niej.

  • git rebase wspomina:
    Uwaga że rebase połączyć prace odtwarzając każdy popełnić z branży pracuje na górze <upstream> gałęzi.
    Z tego powodu, gdy konflikt scalania się dzieje:

    • strona zgłoszona jako nasz jest tak daleko rebased serii, począwszy <upstream>,
    • i ich jest oddział pracuje.
      Innymi słowy, boki są zamieniane na.

git rebase powtórki popełnić każdy z branży pracuje na górze <upstream> gałęzi.

Jeśli pogodzić obie definicje:

  • z commity pochodzące z SVN są tymi, na szczycie której lokalne commity Git są odtwarzane. Są one częścią "dotychczasowej serii" i są określane jako "nasze" (w twoim przypadku plik test.txt z zawartością bar)
  • działająca gałąź (zawierająca polecenia Git nieznane dla SVN, w twoim przypadku, plik test.txt z zawartością baz) jest "ich", a każde z tych lokalnych zatwierdzeń Git jest odtwarzane.

Innymi słowy, SVN czy nie:

  • z „<upstream>” oddział (na szczycie której coś jest odtwarzane, a który jest częścią tej pory rebased zobowiązuje „) jest” nasz ".
  • to, co jest odtwarzane (gałąź robocza) to" ich ".

Dobry mnemonic tip przez CommaToast:

wskazujące cokolwiek HEAD na to "nasze"

(a pierwszą rzeczą git rebase upstream to kasa z upstream oddział na górze którego chcesz dokonać ponownej oceny: HEAD odnosi się do upstream - ours teraz.)


Zamieszanie jest prawdopodobnie pochodzące z roli oddziału pracującego w klasycznym git merge.
Podczas połączenia:

  • z „gałęzi pracy” to jeden zawierający co jest „tak daleko scalone”, i jest uważany za „nasz”,
  • natomiast drugi popełnić reprezentują to, co jest - - nie odtwarzane, ale - scalają się z odgałęzieniem roboczym i są uważane za "ich".

Jak wspomniano na stronie man o numerze git rebase, scalenie podczas zmiany rewersu oznacza zamianę strony.


Innym sposobem, aby powiedzieć to samo jest wzięcie pod uwagę, że:

  • co mamy na wyrejestrowany oddziału jest 'nasz',
  • co mieliśmy (i jest w trakcie scalania lub odtwarzania) jest "ich".

Na seryjnej:

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

, nie zmienić bieżące oddział „B”, więc to, co mamy, to jeszcze co pracowaliśmy na (i scalić z innego oddziału)

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

But przy zmianie bazy, przełączamy strony, ponieważ pierwszą rzeczą, którą robi rebase, jest wykupienie gałęzi oddziału! (Aby odtworzyć bieżące rewizje na wierzchu)

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

git rebase upstream najpierw zmienić HEAD z B do górnej gałęzi HEAD (stąd przełącznik „nasz” i „oni” w porównaniu do poprzedniego " obecny "oddział roboczy.)

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 

, a następnie rebase będzie powtórka 'ich' zobowiązuje się w nowej 'naszej' gałęzi 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 

Jedyny dodatkowy krok z git svn rebase jest to, że svn "pobieranie" jest wykonywane najpierw w zdalnym oddziale Git reprezentującym zatwierdzenia SVN.
Masz początkowo:

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

, najpierw zaktualizować śledzenia oddziału SVN z nowymi commity pochodzących z SVN

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

, następnie przełączyć bieżący oddział na bok SVN (który staje się „nasze „)

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

przed odtwarzając te rewizje pracowałeś na (ale które są teraz«ich»w tym 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 
+9

Wow, co za wspaniała odpowiedź, dzięki! Musiałem całkowicie pominąć tę uwagę na stronie man "git rebase" ... –

+9

+1 za bardzo szczegółową odpowiedź –

+1

Ta odpowiedź powinna zostać zmieniona na kilkaset razy, ale myślę, że niewielu ludzi używa git-svn . Dzięki @VonC! – epologee

Powiązane problemy