Я использую мерзавца-svn, и я заметил это, когда я должен зафиксировать конфликт слияния после выполнения a 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"
Это кажется соответствующим тому, что делает rebase.
git svn rebase
получит ревизии из SVN-родителя текущего HEAD и пересоздаст текущую (нефиксированную в SVN) работу в соответствии с ними.
git rebase
упоминает:
.
Обратите внимание, что слияние rebase работает путём воспроизведения каждого коммита из рабочей ветки поверх ветки
.
Из-за этого, когда происходит конфликт слияния:
,git rebase воспроизводит каждый коммит из рабочей ветви поверх
ветви.
Если согласовать оба определения:
test.txt
файл с bar
содержимым)test. txt
файл с baz
содержимым) является "своей", и каждый из этих локальных Git-коммитов воспроизводится. Другими словами, SVN или нет:
" (поверх которой воспроизводится всё, что угодно, и которая является частью пока что ребазированных коммитов") является "нашей". Хорошая мнемоническая подсказка от CommaToast:
на что бы ни указывал HEAD, это "наше"
(и первое, что делает git rebase upstream
, это проверяет upstream
ветку, поверх которой вы хотите сделать rebase: HEAD относится к upstream
-- ours
now.)
Путаница, вероятно, происходит из-за роли рабочей ветки в классическом git merge
.
При слиянии:
Как упоминается на странице руководства git rebase
, слияние во время 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
Но при ребазе, мы меняем сторону, потому что первое, что делает ребаз, это проверяет восходящую ветку! (чтобы воспроизвести текущие коммиты поверх неё)
x--x--x--x--x(*) <- current branch B
\
\
\--y--y--y <- upstream branch
A git rebase upstream
сначала изменит HEAD
ветки B на ветку upstream HEAD
(отсюда переключение "наших" и "их" по сравнению с предыдущей "текущей" рабочей веткой. )
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
, а затем 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