Чому значення "наш" і "їх" зворотне за допомогою git-svn


90

Я використовую git-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"

Джут оновив мою відповідь безліччю діаграм, щоб краще проілюструвати "нашу" та "їх" сторони.
VonC

1
Див. Також github.com/git/git/commit/…
VonC

Відповіді:


230

Здається, це відповідає тому, що робить перебазування.

  • 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 :

на що вказує HEAD, це "наше"

(і перше, що git rebase upstreamробить a , щоб перевірити 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

9
Ого, яка чудова відповідь, дякую! Я, мабуть, повністю пропустив це зауваження на git rebaseсторінці
довідок

@epologee: ласкаво просимо. Також корисно, коли ви використовуєте лише git, щоб зрозуміти, що відбувається під час перебазування та злиття. І це додає до висхідного визначенням: stackoverflow.com/questions/2739376 / ...
VonC

5
Боже!!! Який вид наркотиків приймав Торвальдс? Це занадто складно! Git - дуже небезпечний інструмент. Ви можете легко знищити всю свою роботу, якщо спробуєте використати сторонні знання або свою інтуїцію. Розробка програмного забезпечення пішла вниз із черв'ячної ями!
ATL_DEV

@ user148298 У цій функції немає нічого поганого. Вам не потрібно знати всіх подібних речей, якщо ви не є експертом у галузі Git. І якщо вам потрібні розширені функції, вам доведеться це вивчити спочатку.
Earth Engine
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.