“我们的”到底是什么意思?和“;theirs"在git中?

这听起来可能是一个太基本的问题,但我一直在寻找答案,现在我比以前更困惑了。

当我的分支合并到我的另一个分支时,“我们的”和“他们的”在git中是什么意思? 两个分支都是“我们的”。< / p >

在合并冲突中,“我们的”总是显示两个版本的上部吗?

“我们的”是否总是指合并开始时HEAD所指向的分支?如果是这样,那么为什么不使用一个明确的所有格,如“当前分支的”,而不是使用一个所有格代词,如“我们的”,这是指模棱两可的(因为两个分支在技术上都是我们的)?

或者只是使用分支名称(而不是说“我们的”,而是说“本地主人的”或类似的)?

最让我困惑的部分是,如果我在一个特定分支的.gitattributes文件中指定。让我们说在测试部门中,我有以下.gitattributes文件:

config.xml merge=ours

现在我签出并将HEAD指向,然后合并到测验中。既然是我们的,而测验的.gitattributes没有签出,它甚至会有影响吗?如果它确实有影响,因为现在是“我们的”,那么会发生什么?

169802 次浏览

我怀疑你在这里感到困惑,因为它从根本上令人困惑。更糟糕的是,当你在做rebase时,我们/他们的所有东西都转换了角色(变成了倒退)。

最终,在git merge过程中,“ours”分支指的是你要合并的分支:

git checkout merge-into-ours

“their”分支指的是你要合并的(单个)分支:

git merge from-theirs

在这里,“ours”和“their”是有意义的,因为即使“their”可能是你的,“their”也不是你运行git merge的那个。

虽然使用实际的分支名称可能很酷,但在更复杂的情况下就不行了。例如,你可以这样做:

git checkout ours
git merge 1234567

通过原始commit-ID进行合并。更糟糕的是,你甚至可以这样做:

git checkout 7777777    # detach HEAD
git merge 1234567       # do a test merge

在这种情况下,涉及到没有分支名称!

我认为这在这里没有什么帮助,但实际上,在gitrevisions语法中,你可以在冲突合并期间通过数字引用索引中的单个路径

git show :1:README
git show :2:README
git show :3:README

阶段#1是文件的共同祖先,阶段#2是目标分支版本,阶段#3是您要合并的版本。


“ours”和“their”的概念在rebase期间交换的原因是rebase通过做一系列的筛选工作,进入一个匿名分支(分离HEAD模式)。目标分支是匿名分支,而merge-from分支是你的原始(预重基)分支:所以“——our”意味着匿名的一个重基正在构建,而“——their”意味着“我们的分支正在重基”。


对于gitattributes条目:它可以有一个影响:“ours”实际上在内部意味着“使用阶段#2”。但正如你所注意到的,它实际上并没有到位,所以它不应该在这里有影响…除非在开始之前将它复制到工作树中。

另外,顺便说一下,这适用于我们和他们的所有使用,但有些是在整个文件级别(-s ours用于合并策略;git checkout --ours在合并冲突期间),有些是在一块一块的基础上(-X ours-X theirs-s recursive合并期间)。这可能无助于解决任何困惑。

不过,我从来没有想过一个更好的名字。并且:参见VonC的回答到另一个问题,其中git mergetool为这些引入了更多的名称,称它们为“本地”和“远程”!

Git中的'我们的'指的是原始的工作分支,它具有Git历史的权威/规范部分。

'他们的'指的是保存工作以便成为变基的版本(更改将被重播到当前分支)。

这可能看起来是交换给那些没有意识到做重基(例如git rebase)实际上是暂停你的工作(即他们的),以便重放到规范/主历史(即我们的)上,因为我们将我们的更改作为第三方工作重基。

根据f303016提交git-checkout的文档在Git >=2.5.1中进一步澄清:

< p > --ours --theirs < / p > 当从索引中检出路径时,检出阶段#2 ('ours')或#3 ('their ')用于未合并的路径

注意,在git rebasegit pull --rebase期间,'ours'和'their '可能会出现互换;--ours给出了来自重新基于的变更的分支的版本,而--theirs给出了来自保存正在重新基于的工作的分支的版本。

这是因为rebase在一个工作流中使用,该工作流将远程的历史记录视为共享的规范历史记录,并将在您要重基的分支上完成的工作视为要集成的第三方工作,并且在重基期间您临时承担了规范历史记录的保存者的角色。作为规范历史记录的保存者,您需要从远程以ours(即。"我们共享的规范历史"),而你在你的分支theirs(即。“一个贡献者的工作在上面”)。

对于git-merge,它的解释如下:

我们的

这个选项迫使冲突块自动解决干净,有利于我们的版本。来自另一棵树的与我们这边不冲突的更改会反映到合并结果中。对于二进制文件,整个内容都是从我们这边取的。

这不应该与我们的合并策略相混淆,后者甚至根本不查看另一棵树包含什么。它抛弃了另一棵树所做的一切,宣称我们的历史包含了它所发生的一切。

他们的

这是我们的反面。

此外,这里解释了如何使用它们:

合并机制(git mergegit pull命令)允许使用-s选项选择后端合并策略。一些策略也可以有自己的选项,可以通过将-X<option>参数传递给git merge和/或git pull来传递。


所以有时它会让人困惑,例如:

  • git pull origin master,其中-Xours是我们的本地分支,-Xtheirs是他们的(远程)分支
  • git pull origin master -r,其中-Xours是他们的(远程),-Xtheirs是我们的

第二个例子与第一个相反,因为我们在远程分支的基础上重新建立了分支,所以我们的起点是远程分支,我们的更改被视为外部的。

类似的git merge策略(-X ours-X theirs)。

  • 我们的:这是你当前所在的分支。
  • 他们的:这是在操作中使用的另一个分支。

因此,如果你在分支发布/ 2.5上,并且你将分支特性/新的按钮合并到它中,那么在发布/ 2.5中找到的内容就是我们的所指向的内容,而在特性/新的按钮中找到的内容就是他们的所指向的内容。在合并操作中,这是非常直接的。

大多数人陷入的唯一问题是换基的情况。如果您执行的是re-base而不是普通的合并,则角色将交换。这是怎么回事?嗯,这完全是由重基工作的方式引起的。想想rebase是这样工作的:

  1. 自你最后一次拉之后所做的所有提交都被移动到它们自己的分支,让我们将其命名为BranchX
  2. 签出当前分支的头,丢弃任何本地分支
  3. . . .
  4. 现在BranchX上的每个提交都是按照从旧到新的顺序挑选到当前分支的。
  5. BranchX再次被删除,因此不会在任何历史记录中显示。

当然,事实并非如此,但这对我来说是一个很好的心智模型。如果你看第二和第三,你就会明白为什么角色互换了。在第2点,你的当前分支现在是来自服务器的分支,没有你的任何更改,所以这是我们的(你所在的分支)。你所做的更改现在在一个不同的分支上,不是你当前的分支(BranchX),因此这些更改(尽管是你所做的更改)是他们的(在你的操作中使用的另一个分支)。

这意味着如果你合并,你想让你的改变总是赢,你会告诉git总是选择“我们的”,但如果你重新基数,你想让你的所有改变总是赢,你告诉git总是选择“他们的”。

我知道这个问题已经有答案了,但是这个问题让我困惑了很多次,所以我建立了一个小的参考网站来帮助我记住: https://nitaym.github.io/ourstheirs/ < / p >

以下是基本原则:

合并:

$ git checkout master
$ git merge feature

如果你想在master中选择版本:

$ git checkout --ours codefile.js

如果你想在feature中选择版本:

$ git checkout --theirs codefile.js

重置:

$ git checkout feature
$ git rebase master

如果你想在master中选择版本:

$ git checkout --ours codefile.js

如果你想在feature中选择版本:

$ git checkout --theirs codefile.js

(当然,这是针对完整的文件)

git checkout的用法:

-2, --ours            checkout our version for unmerged files
-3, --theirs          checkout their version for unmerged files
-m, --merge           perform a 3-way merge with the new branch

在解决合并冲突时,可以执行git checkout --theirs some_filegit checkout --ours some_file来分别将文件重置为当前版本和传入版本。

如果你已经执行了git checkout --ours some_filegit checkout --theirs some_file,并且想要将文件重置为文件的3向合并版本,你可以执行git checkout --merge some_file

我知道这不能解释它的意思,但我给自己做了一个小图像,作为参考,提醒使用哪个:

enter image description here

希望能有所帮助!

PS -给一个检查也在Nitay的回答🙂的链接

我将把我的备忘录贴在这里,因为我必须一次又一次地回到这里。

你是一个不能合并到master的开发人员,只能使用feature分支。

案例1:主人是国王。你想要刷新你的feature分支(= rebase to master),因为master包含新的依赖项更新,你想要覆盖你的适度更改。

git checkout master
git pull


git checkout feature
git rebase -X ours master

你想要将你的feature分支重置为master changes。但是您比您的同事做得更多,并且希望优先使用您自己的更改。

git checkout master
git pull


git checkout feature
git rebase -X theirs master

重要提示:正如你所看到的,正常的开发人员应该更喜欢rebase,并像每天早上锻炼/喝咖啡一样重复它。

场景2。Merging-sensei:你是一个团队领导,想要合并其他分支,并将合并的结果直接推给一个主分支。master是一个你要改变的分支。

案例1:主人是国王你想合并第三方分支,但是master是优先级。feature是你的前辈做的分支。

git checkout feature
git pull


git checkout master
git merge -X ours feature

当你的高级开发人员发布了一个很酷的feature,你想在master分支中覆盖旧的东西。

git checkout feature
git pull


git checkout master
git merge -X theirs feature

记住:在午夜记住该选择哪一个:master总是ours。而theirs是他们所做的feature

没有确切的含义,正是因为这些术语意味着相反的事情,这取决于你是合并还是重基。思考两个分支的自然方式是“我的工作”。还有“别人的作品”。混淆这种分类的术语选择绝对是git中最糟糕的设计选择。它一定是受到了会计“信用”的启发。和“;debit"或“;assets"和“;liabilities"-同样的头疼。

澄清一下——如上所述,当变基时,意义是相反的,所以如果你看到

<<<<<<< HEAD
foo = 12;
=======
foo = 22;
>>>>>>> [your commit message]

解析使用'mine' ->Foo = 12

解决使用'their ' ->Foo = 22