Почему смысл "наших" и "их" отменяется с помощью git -svn

Я использую git -svn, и я заметил, что когда мне нужно исправить конфликт слияния после выполнения git svn rebase, значение параметров --ours и --theirs, например, git checkout отменяется. То есть, если есть конфликт, и я хочу сохранить версию, полученную с сервера SVN, и выбросить изменения, которые я сделал локально, я должен использовать ours, когда я ожидаю, что это будет theirs.

Почему это?

Пример:

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"

Ответ 1

Это похоже на то, что делает rebase.

  • git svn rebase будет получать ревизии от родителя SVN текущего HEAD и восстанавливает текущую (незадействованную SVN) работу против он.

  • git rebase упоминает:
    Обратите внимание, что слияние ребай работает, переигрывая каждую фиксацию из рабочей ветки поверх ветки <upstream>.
    Из-за этого, когда происходит конфликт слиянием:

    • Сторона, указанная как наша, представляет собой так называемую перевыпущенную серию, начиная с <upstream>,
    • , а их - рабочая ветвь.
      Другими словами, стороны обмениваются.

git rebase повторяет каждую фиксацию из рабочей ветки поверх ветки <upstream>.

Если вы согласовываете оба определения:

  • Котировки, исходящие из SVN, - это те, на вершинах которых локальные компиляции Git воспроизводятся. Они являются частью серии "so-far rebased" и называются "нашими" (в вашем случае, файл test.txt с содержимым bar)
  • рабочая ветка (содержащая Git фиксирует неизвестный SVN, в вашем случае, файл test.txt с содержимым baz) является "их" , и каждая из этих локальных коммитов Git воспроизводится.

Другими словами, SVN или нет:

  • ветвь "<upstream>" (поверх которой все что-либо воспроизводится и которая является частью так называемых сокращенных коммитов) " наша".
  • то, что воспроизводится (рабочая ветвь), их.

Хороший мнемонический совет от CommaToast:

любой HEAD, указывающий на "наш"

(и, прежде всего, git rebase upstream выполняет проверку ветки upstream, поверх которой вы хотите переустановить: HEAD теперь относится к upstream - ours.)


Путаница, скорее всего, происходит от роли рабочей ветки в классическом git merge.
Когда вы объединяетесь:

  • "рабочая ветвь" - это та, которая содержит "до сих пор объединенную" и считается "нашей" ,
  • в то время как другой фиксатор представляет то, что есть - не воспроизводится, а - сливается поверх рабочей ветки и считается "их" .

Как упоминается страница man git rebase, слияние во время переустановки означает, что сторона обменивается.


Еще один способ сказать то же самое - подумать, что:

  • то, что у нас есть на проверенной ветке, наш,
  • то, что у нас было (и оно сливается или переигрывается) - это их.

При слиянии:

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

мы не меняем текущую ветвь "B", поэтому то, что мы имеем, - это то, над чем мы работали (и мы сливаемся с другой ветвью)

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

Но на rebase, мы переключаем сторону, потому что первое, что нужно сделать, это проверка ветки upstream! (чтобы воспроизвести текущий ток на вершине)

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

A git rebase upstream сначала изменит HEAD B на ветвь вверх по течению HEAD (следовательно, переключатель 'ours' и 'theirs' по сравнению с предыдущей "текущей" рабочей ветвью.)

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 on it

а затем rebase будет воспроизводить "свои" фиксации в новой "нашей" ветки 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

Единственный дополнительный шаг с git svn rebase заключается в том, что svn "fetch" выполняется сначала на удаленной ветке Git, представляющей записи SVN.
Вы изначально:

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

вы сначала обновляете ветвь отслеживания SVN с новыми коммитами, поступающими из SVN

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

то вы переключите текущую ветвь на сторону SVN (которая становится "нашей" )

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

перед воспроизведением коммитов, над которыми вы работали (но которые теперь являются "их" во время этой перезагрузки)

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