왜“우리”와“자신”의 의미가 git-svn으로 바뀌 었습니까?


90

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"

Jut는 "우리"와 "그들의"측면을 더 잘 설명하기 위해 많은 다이어그램으로 내 대답을 업데이트했습니다.
VonC

답변:


230

그것은 rebase가하는 일과 일치하는 것 같습니다.

  • git svn rebase 현재 HEAD의 SVN 상위에서 개정을 가져오고 현재 (SVN에 커밋되지 않은) 작업을 리베이스합니다.

  • git rebase언급하지 않습니다.
    리베이스 병합은 브랜치 상단의 작업 브랜치에서 각 커밋을 재생하여 작동합니다 <upstream>.
    이 때문에 병합 충돌이 발생하는 경우 :

    • 우리의 것으로보고 된 측면은로 시작하는 지금까지 리베이스 된 시리즈입니다<upstream> .
    • 그리고 그들의 것은 작업 지점 입니다.
      즉, 측면이 서로 바뀝니다 .

git rebase는 <upstream>분기 상단의 작업 분기에서 각 커밋을 재생합니다 .

두 정의를 모두 조정하는 경우 :

  • SVN에서 오는 커밋은 로컬 Git 커밋이 재생되는 맨 위에있는 커밋입니다. 그것들은 "지금까지 리베이스 된 시리즈"의 일부이며 "우리"로 참조됩니다 (귀하의 경우 콘텐츠가 있는 test.txt파일 bar).
  • 작업 브랜치 (SVN에 알려지지 않은 Git 커밋 포함, 귀하의 경우 콘텐츠가 있는 test.txt파일 baz포함)는 "자신의"로컬 Git 커밋이 재생되고 있습니다.

즉, SVN 여부 :

  • " <upstream>"브랜치 (위에 무엇이든지 재생되고 지금까지 리베이스 된 커밋의 일부 임)는 " ours "입니다.
  • 재생되는 것은 (작업 분기) " theirs "입니다.

좋은 기억을 돕는 팁 으로 CommaToast :

HEAD가 가리키는 것은 "우리"입니다.

(그리고 제일 먼저 A는 git rebase upstream그것을 체크 아웃 않습니다 upstream당신이 리베이스 할 위에 지점 : 머리를 말한다 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

그러나 REBASE에 REBASE가 맨 처음에하는 일이 업스트림 브랜치를 체크 아웃하기 때문에, 우리는 측면을 전환! (현재 커밋을 재생하려면)

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 "fetch"가 먼저 수행된다는 것입니다.
처음에 :

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... 사람 페이지
마크 Liyanage에게

@epologee : 천만에요. 또한 git 만 사용하는 경우 리베이스와 병합 중에 무슨 일이 일어나는지 이해하는 데 유용합니다. 그리고 그것은 업스트림 정의에 추가됩니다 : stackoverflow.com/questions/2739376/…
VonC

5
맙소사 !!! Torvalds는 어떤 종류의 약을 복용 했습니까? 이것은 너무 복잡합니다! Git은 매우 위험한 도구입니다. 외부 지식이나 직관을 사용하면 모든 작업을 쉽게 파괴 할 수 있습니다. 소프트웨어 개발이 웜홀에서 사라졌습니다!
ATL_DEV

@ user148298이 함수에는 잘못된 것이 없습니다. git 전문가가 아니라면 그런 모든 것을 알 필요가 없습니다. 고급 기능이 필요한 경우 먼저 배워야합니다.
Earth Engine
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.