为什么git-svn会颠倒“我们”和“他们的”的意思 [英] Why is the meaning of “ours” and “theirs” reversed with git-svn

查看:86
本文介绍了为什么git-svn会颠倒“我们”和“他们的”的意思的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用git-svn,我注意到当我在执行 git svn rebase 后必须修复合并冲突时, --ours - 他们的选项,例如 git checkout 是相反的。也就是说,如果存在冲突,我想保留来自SVN服务器的版本并丢弃我在本地进行的更改,则必须使用我们的,当我预计它会是他们的



这是为什么?



示例:

  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克隆文件:// $ PWD / svnrepo gitwc
cd svnwc
回音棒> 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
#显示bar,但我期望baz

git checkout - 他们的test.txt
cat test.txt
#显示baz,但我期望bar


解决方案




  • git svn rebase 将从当前HEAD的SVN父节点获取修订版本,并将当前版本(未提交到SVN)重定向到它。


  • git rebase 确实提到:

    请注意,重新合并合并的工作原理是在<上游> 分支。

    因此,发生合并冲突时:


    • 边r以我们的身份进行推介是迄今为止重新推出的系列,从<上游>

    • 以及他们是工作分支


      换句话说,双方交换



  • $ b


    git rebase在<上游>的顶部重新运行来自工作分支的每个提交 code>分支。


    如果您协调两个定义:


    • 来自SVN的提交是本地Git提交被重播的那些提交。它们是迄今为止重新发布的系列的一部分,并且被引用为我们的(在您的情况下, test.txt 文件,其中 bar content)

    • 工作分支(包含Git未知的SVN,在你的情况下, test.txt baz 内容)是他们的,并且每个本地Git提交都正在重播。 b
      $ b换句话说,SVN与否:

      • <上游> 分支(在其上重播任何内容,并且是迄今为止重新发布的提交的一部分)是我们的。 $ b
      • 正在重播的内容(工作分支)是他们的





      C提供的助记符提示 ommaToast :


      HEAD指向的是我们的


      (以及 git rebase upstream )的第一件事情是检出上游你想要重新分配的分支:HEAD引用上游 - 我们的






      混淆可能来自经典分支 git merge
      当您合并时:


      • 工作分支是包含迄今合并,并且被认为是我们的,而另一个提交代表什么是 - 没有重播,但是 - 合并在工作分支之上,并且被视为他们的 。


      随着 git rebase 手册页的提及,意思我们一边交换一边。






      另一种说同样事情的方式是考虑:




      • 我们在结帐分支上有我们',

      • 我们拥有的(以及正在合并或重播的)是他们的'。





      合并

       <$ c (*)=当前分支B('*'= HEAD)
      \
      \
      \ --y - y - y< - 其他分支合并

      ,我们不改变当前分支'B',所以我们所拥有的仍然是我们正在做的事情(并且我们从另一个分支合并)

        x  -  x  -  x  -  x  -  x --------- o(*)MERGE,仍然在分支上B 
      \ ^ /
      \ ours /
      \ /
      --y - y - y - /
      ^
      thei r






      但是我们转换方,因为rebase做的第一件事是检查上游分支! (以重播当前的提交) -

        x  -  x  -  x  -  x  -  x(* )<  - 当前分支B 
      \
      \
      \ - y - y - y < - 上游分支

      git rebase upstream 首先会更改 HEAD B到上游分支 HEAD (因此,与我们之前的当前工作分支相比,'我们'和'他们'的切换)

        x  -  x  -  x  -  x  -  x < - 前当前分支,新增他们的
      \
      \
      \ - y - y - y(*)< - 具有B重置的上游分支,
      new我们的,重新播放x的

      ,然后rebase会重新播放'他们'提交新的'我们的'B分支:

        x  -  x..x..x..x < - 旧的他们的提交,现在可以通过reflog获得幽灵
      \
      \
      \ - y-- y - y - x' - x' - x'(*)< - 更新HEAD的分支B(我们的)
      ^
      |
      上游分支






      唯一的额外步骤使用 git svn rebase 是,首先在表示SVN提交的Git远程分支上执行svnfetch。

      您最初有:

        x  -  x  -  x  -  x  -  x(*)< - 当前分支B ,现在是我们的。 
      \
      \
      \ - y - y - y < - SVN跟踪分支,现在他们的



      ,您首先使用来自SVN的新提交更新SVN跟踪分支

        x  -  x  -  x  -  x  -  x(*)< - 当前分支B,仍然是我们的,不是很长的
      \
      \
      \ - y - y - y - y' - y'< - SVN跟踪分支已更新

      ,那么你将当前分支切换到SVN端(它变成我们)

        x-x-x-x-x < - 对于B,现在在变基期间他们
      \
      \
      \ - y- -y - y - y' - y'(*)< - SVN跟踪分支已更新,分支B:
      现在我们的(这是我们现在拥有的)

      ,在重放您正在工作的提交之前o ñ(但现在是他们的他们在这个rebase期间)

        x  -  x..x..x..x <  - 老他们的提交,现在是幽灵,可通过reflogs获得
      \
      \
      \ - y - y - y - y' - y' - x' - x' - x'(*)< - 带有HEAD的分支B更新(我们的)
      ^
      |
      上游SVN跟踪分支


      I use git-svn and I noticed that when I have to fix a merge conflict after performing a git svn rebase, the meaning of the --ours and --theirs options to e.g. git checkout is reversed. That is, if there's a conflict and I want to keep the version that came from the SVN server and throw away the changes I made locally, I have to use ours, when I would expect it to be theirs.

      Why is that?

      Example:

      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"
      

      解决方案

      That seems consistent with what a rebase does.

      • git svn rebase will fetches revisions from the SVN parent of the current HEAD and rebases the current (uncommitted to SVN) work against it.

      • git rebase does mention:
        Note that a rebase merge works by replaying each commit from the working branch on top of the <upstream> branch.
        Because of this, when a merge conflict happens:

        • the side reported as ours is the so-far rebased series, starting with <upstream>,
        • and theirs is the working branch.
          In other words, the sides are swapped.

      git rebase replays each commit from the working branch on top of the <upstream> branch.

      If you reconcile both definitions:

      • the commits coming from SVN are the ones on top of which local Git commits are replayed. They are part of the "so-far rebased series", and are referenced as "our" (in your case, the test.txt file with bar content)
      • the working branch (containing Git commits unknown to SVN, in your case, the test.txt file with baz content) is "their", and each of those local Git commits are being replayed.

      In other words, SVN or not:

      • the "<upstream>" branch (on top of which anything is replayed, and which is part of the so far rebased commits") is "ours".
      • what is being replayed (the working branch) is "theirs".

      Good mnemonic tip by CommaToast:

      whatever HEAD's pointing to is "ours"

      (and the first thing a git rebase upstream does it to checkout the upstream branch on top of which you want to rebase: HEAD refers to upstream -- ours now.)


      The confusion is likely coming from the role of the working branch in a classic git merge.
      When you are merging:

      • the "working branch" is the one containing what is "so far merged", and is considered as "our",
      • while the other commit represent what is being -- not replayed but -- merge on top of the working branch, and considered as "their".

      As the git rebase man page mentions, a merge during a rebase means the side are swapped.


      Another way to say the same thing is to consider that:

      • what we have on the checked out branch is 'ours',
      • what we had (and is being merged or replayed) is 'theirs'.

      On a merge:

      x--x--x--x--x(*) <- current branch B ('*'=HEAD)
          \
           \
            \--y--y--y <- other branch to merge
      

      , we don't change the current branch 'B', so what we have is still what we were working on (and we merge from another branch)

      x--x--x--x--x---------o(*)  MERGE, still on branch B
          \       ^        /
           \     ours     /
            \            /
             --y--y--y--/  
                     ^
                    their
      


      But on a rebase, we switch side because the first thing a rebase does is to checkout the upstream branch! (to replay the current commits on top of it)

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

      A git rebase upstream will first change HEAD of B to the upstream branch HEAD (hence the switch of 'ours' and 'theirs' compared to the previous "current" working branch.)

      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
      

      , and then the rebase will replay 'their' commits on the new 'our' B branch:

      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
      


      The only extra step with git svn rebase is that a svn "fetch" is performed first on the Git remote branch representing SVN commits.
      You have initially:

      x--x--x--x--x(*) <- current branch B, "ours" for now.
          \                                   
           \
            \--y--y--y <- SVN tracking branch, "theirs for now"
      

      , you first update the SVN tracking branch with new commits coming from SVN

      x--x--x--x--x(*) <- current branch B, still "ours", not for long
          \                                   
           \
            \--y--y--y--y'--y' <- SVN tracking branch updated
      

      , then you switch the current branch to the SVN side (which becomes "ours")

      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")
      

      , before replaying the commits you were working on (but which are now "theirs" during that rebase)

      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
      

      这篇关于为什么git-svn会颠倒“我们”和“他们的”的意思的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆