Почему значения «наш» и «их» меняются местами с помощью git-svn

91

Я использую 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"
Марк Лиянаге
источник
Я обновил свой ответ множеством диаграмм, чтобы лучше проиллюстрировать «нашу» и «их» стороны.
VonC
1
См. Также github.com/git/git/commit/…
VonC

Ответы:

232

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

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

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

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

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

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

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

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

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

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

все, на что указывает ГОЛОВА, "наше"

(и первое, что a git rebase upstreamделает это, чтобы проверить upstreamветку, поверх которой вы хотите перебазировать: HEAD ссылается upstream- oursсейчас.)


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

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

Как 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

Но при перебазировании мы переключаемся на сторону, потому что первое, что делает перебаз, - проверяет восходящую ветвь! (чтобы воспроизвести поверх него текущие коммиты)

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

A git rebase upstreamсначала изменит HEADB на восходящую ветвь 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

, а затем перебазирование воспроизведет 'их' коммиты в новой 'нашей' ветке 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
VonC
источник
9
Вау, какой отличный ответ, спасибо! Я, должно быть, полностью пропустил это замечание на git rebaseстранице руководства ...
Марк Лиянаге
@epologee: пожалуйста. Это также полезно, когда вы используете только git, чтобы понять, что происходит во время перебазирования и слияния. И это добавляет к определению восходящего потока: stackoverflow.com/questions/2739376/…
VonC
5
О Господи!!! Какие лекарства принимал Торвальдс? Это слишком сложно! Git - очень опасный инструмент. Вы можете легко разрушить всю свою работу, если попытаетесь использовать сторонние знания или свою интуицию. Разработка программного обеспечения провалилась в червоточину!
ATL_DEV
@ user148298 В этой функции нет ничего плохого. Вам не обязательно знать все эти вещи, если вы не являетесь экспертом по git. И если вам действительно требуются расширенные функции, вам нужно сначала изучить их.
Earth Engine