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