为什么“我们的”和“他们的”的含义用 git-svn 颠倒了

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2959443/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 08:30:10  来源:igfitidea点击:

Why is the meaning of “ours” and “theirs” reversed with git-svn

gitgit-svn

提问by Marc Liyanage

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 --oursand --theirsoptions to e.g. git checkoutis 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.

我使用 git-svn 并且我注意到当我必须在执行 a 后修复合并冲突时, eg和选项git svn rebase的含义是相反的。也就是说,如果存在冲突并且我想保留来自 SVN 服务器的版本并丢弃我在本地所做的更改,我必须使用,而我希望它是.--ours--theirsgit checkoutourstheirs

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"

回答by VonC

That seems consistent with what a rebase does.

这似乎与 rebase 的作用一致。

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

  • git rebasedoes 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 svn rebase将从当前 HEAD 的 SVN 父级获取修订,并将当前(未提交给 SVN)的工作重新绑定到它。

  • git rebase确实提到:
    请注意,rebase 合并通过重放分支顶部的工作分支的每个提交来工作<upstream>
    因此,当发生合并冲突时:

    • 报道为我们的一方是迄今为止重新调整的系列,从<upstream>
    • 他们是工作分支
      换句话说,双方互换

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

git rebase 重放来自分支顶部的工作分支的每个提交<upstream>

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.txtfile with barcontent)
  • the working branch (containing Git commits unknown to SVN, in your case, the test.txtfile with bazcontent) is "their", and each of those local Git commits are being replayed.
  • 来自 SVN 的提交是在其上重放本地 Git 提交的提交。它们是“迄今为止重新定位的系列”的一部分,并被称为“我们的”(在您的情况下,是test.txt包含bar内容的文件)
  • 工作分支(包含 SVN 未知的 Git 提交,在您的情况下,是test.txt包含baz内容的文件)是“他们的”,并且正在重播每个本地 Git 提交。

In other words, SVN or not:

换句话说,SVN 与否:

  • 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".
  • <upstream>”分支(在其上重放任何内容,并且是迄今为止重新提交的一部分”)是“我们的”。
  • 正在重播的(工作分支)是“他们的”。


Good mnemonic tipby CommaToast:

记忆提示通过CommaToast

whatever HEAD's pointing to is "ours"

HEAD 所指的都是“我们的”

(and the first thing a git rebase upstreamdoes it to checkout the upstreambranch on top of which you want to rebase: HEAD refers to upstream-- oursnow.)

(并且 agit rebase upstream做的第一件事是检出upstream要在其上变基的分支:HEAD 指的是upstream--ours现在。)



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

混淆可能来自经典中工作分支的角色git merge
合并时:

  • 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 rebaseman page mentions, a merge during a rebase means the side are swapped.

正如git rebase手册页所提到的,在变基期间进行合并意味着交换了一侧。



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

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

  • what we haveon 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)

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

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)

但是在 rebase 上,我们换边了,因为 rebase 做的第一件事就是检出上游分支!(在其上重放当前提交)

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

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

Agit 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

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

,然后 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


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

唯一的额外步骤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"

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

,您首先使用来自 SVN 的新提交更新 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")

,然后将当前分支切换到 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")

, 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