git中"我们的"和"他们的"的确切含义是什么?

Com*_*ast 287 git merge

这可能听起来像是一个基本的问题,但我已经寻找答案,我现在比以前更困惑.

当我的分支合并到我的另一个分支时,git中的"我们的"和"他们的"是什么意思?两个分支都是"我们的".

合并冲突是"我们的"总是显示两个版本的上部?

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

或者只是使用分支名称(而不是说"我们的"只是说"本地主人"等)?

对我来说最令人困惑的部分是我在特定分支的.gitattributes文件中指定.让我们说在测试分支中我有以下.gitattributes文件:

config.xml merge=ours
Run Code Online (Sandbox Code Playgroud)

现在我结账并指出HEAD为master然后合并测试.由于master是我们的,并且test的.gitattributes没有签出,它甚至会产生影响吗?如果它确实有效果,因为主人现在是"我们的",那么会发生什么?

tor*_*rek 327

我怀疑你在这里很困惑,因为它从根本上造成了混乱.更糟糕的是,当你做一次变装时,整个我们/他们的东西会切换角色(变得倒退).

最终,期间git merge,在"我们的"分支是指你归并的分支为:

git checkout merge-into-ours
Run Code Online (Sandbox Code Playgroud)

而"他们的"分支指的是您正在合并的(单个)分支:

git merge from-theirs
Run Code Online (Sandbox Code Playgroud)

这里"我们"和"他们"有一定道理,因为,即使"他们"可能是你的,无论如何,"他们"是不是你是我的唯一的,当你跑了git merge.

虽然使用实际的分支名称可能非常酷,但在更复杂的情况下会崩溃.例如,您可能会执行以下操作:

git checkout ours
git merge 1234567
Run Code Online (Sandbox Code Playgroud)

您通过原始commit-ID合并的位置.更糟糕的是,你甚至可以这样做:

git checkout 7777777    # detach HEAD
git merge 1234567       # do a test merge
Run Code Online (Sandbox Code Playgroud)

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

我认为这在这方面没有什么帮助,但实际上,在gitrevisions语法中,您可以在冲突的合并期间按编号引用索引中的单个路径

git show :1:README
git show :2:README
git show :3:README
Run Code Online (Sandbox Code Playgroud)

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


"我们的"和"他们的"概念之间交换的原因rebase是,rebase通过一系列樱桃选择工作到一个匿名分支(分离的HEAD模式).目标分支是匿名分支,merge-from分支是您的原始(预先变更)分支:因此"--ours"表示匿名的一个rebase正在建立,而"--theirs"表示"我们的分支正在重新定位" .


至于gitattributes条目:它可能会产生影响:"我们的"实际上意味着"在内部使用阶段#2".但正如你所注意到的那样,它当时并不存在,所以它不应该在这里产生影响......好吧,除非你在开始之前将它复制到工作树中.

顺便说一句,这适用于我们和他们的所有用途,但有些是在整个文件级别(-s ours对于合并策略; git checkout --ours在合并冲突期间),有些是在逐个基础上(-X ours或-X theirs在一个-s recursive合并).这可能无助于任何混乱.

不过,我从来没有想过更好的名字.并且:看看VonC对另一个问题的回答,其中git mergetool介绍了更多这些名称,称之为"本地"和"远程"!

  • +1.关于我们和他们在rebase期间被逆转,另见:http://stackoverflow.com/a/2960751/6309和http://stackoverflow.com/a/3052118/6309 (26认同)
  • 我想因为头是心灵的位置,这是身份的来源,这是自我的源泉,所以想到HEAD指向的是"我的"("我们的",从那以后更有意义我想我和HEAD做了两个).如果不出意外,这只是一个很好的助记设备. (15认同)
  • "在这种情况下,没有涉及分支名称!"......所以它应该使用提交注释/哈希.无论它能得到什么.实际上任何东西都会比"我们的"和"他们的"更好.我想知道这个混乱已经消失了几千个小时.git对C++"最令人烦恼的解析"的回答;) (3认同)
  • @torek,这一定是我遇到过的最好的解释之一。感谢您在这个回复中投入了如此多的思考和精力,这非常有帮助。 (2认同)
  • @JānisElmeris:是的,`git stash apply`字面上运行内部`git merge`代码(`git merge-recursive`或`git merge-ort`取决于Git版本)。合并基础是原始提交,“HEAD”是当前提交,“他们的”版本是隐藏的“w”提交。当将 `--index` 与 `git stash pop` 一起使用时,`i` 提交的更改将通过 `git apply` 而不是 `git merge` 来应用。 (2认同)

ken*_*orb 45

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

' 他们 '指的是保存工作以便重新定义的版本(要重播到当前分支的更改).

这可能会被交换到的人谁不知道,做基础重建(例如git rebase)实际上是把你保持工作(这是他们的),以重播到规范/主的历史是我们的,因为我们基础重建我们的作为第三方工作的变化.

为文档git-checkout在GIT中> = 2.5.1进一步明确为每f303016提交:

--ours --theirs

检查索引中的路径时,请查看阶段#2('我们的')或#3('他们')的未合并路径.

请注意,在git rebase和期间git pull --rebase,"我们的"和"他们的"可能会出现交换; --ours从分支中提供更改被重新定义--theirs的版本,同时从保存您正在重新定位的工作的分支中提供版本.

这是因为rebase在将远程历史记录视为共享规范的工作流程中使用,并将您要重新分支的分支上的工作视为要集成的第三方工作,并且您暂时承担在篮板期间,规范历史的守护者.作为规范历史的守护者,您需要从遥控器中查看历史记录ours(即"我们共享的规范历史记录​​"),而您在分支机构中theirs所做的事情(即"一个贡献者的工作在其上").

因为git-merge它以下面的方式解释:

我们的

此选项通过支持我们的版本强制冲突的帅哥干净地自动解决.来自与我们方不冲突的其他树的更改将反映到合并结果中.对于二进制文件,整个内容都来自我们这边.

这不应该与我们的合并策略混淆,后者甚至不会查看其他树包含的内容.它丢弃了另一棵树所做的一切,宣告我们的历史包含了其中发生的一切.

他们的

这与我们的相反.

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

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


所以有时它可能会令人困惑,例如:

  • git pull origin master-Xours我们的本地在哪里 ,-Xtheirs是他们的(远程)分支
  • git pull origin master -r-Xours他们在哪里(遥远),-Xtheirs是我们的

所以第二个例子与第一个例子相反,因为我们将我们的分支重新定位在远程分支之上,所以我们的起点是远程分支,我们的变化被视为外部分支.

git merge策略(-X ours和-X theirs)类似.

  • 该答案似乎已过期=&gt;“ git merge --ours”不是有效的选项 (2认同)
  • 你对 rebase 向后的解释非常有道理,我可能不用谷歌就能记住它。感谢您! (2认同)

Nit*_*tay 40

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

以下是基础知识:

合并:

$ git checkout master 
$ git merge feature
Run Code Online (Sandbox Code Playgroud)

如果要选择以下版本master:

$ git checkout --ours codefile.js
Run Code Online (Sandbox Code Playgroud)

如果要选择以下版本feature:

$ git checkout --theirs codefile.js
Run Code Online (Sandbox Code Playgroud)

底垫:

$ git checkout feature 
$ git rebase master 
Run Code Online (Sandbox Code Playgroud)

如果要选择以下版本master:

$ git checkout --ours codefile.js
Run Code Online (Sandbox Code Playgroud)

如果要选择以下版本feature:

$ git checkout --theirs codefile.js
Run Code Online (Sandbox Code Playgroud)

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

  • 该网站非常有帮助。流程图风格和颜色编码的文字使网站比 SO 答案更容易理解。谢谢。 (4认同)
  • 谢谢,这就是我一直在寻找的简单示例解释。其他答案谈论了太多关于为什么你可能会感到困惑,以及这些术语的含义等等,以至于答案本身变得令人困惑。 (2认同)

Kam*_*her 13

我知道它没有解释含义,但我给自己做了一个小图像,作为参考以提醒使用哪个:

在此处输入图片说明

希望能帮助到你!

PS - 还要检查Nitay 答案中的链接

  • 我花了太长时间阅读一些关于答案的巨著,你的形象虽然不完美,但以更简洁的方式为我解释了它接近完美。版本 2 可以在这种情况下使用对术语 HEAD 的视觉解释 (2认同)

Pet*_*rth 8

只是为了澄清——如上所述,当重新建立基础时,意义是相反的,所以如果你看到

<<<<<<< HEAD
        foo = 12;
=======
        foo = 22;
>>>>>>> [your commit message]
Run Code Online (Sandbox Code Playgroud)

使用 'mine' -> foo = 12 解决

使用“他们的”解决 -> foo = 22


Mec*_*cki 7

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

因此,如果您使用的是分支版本/2.5,并且将分支功能/新按钮合并到其中,那么发布/2.5中的内容就是我们所指的内容,而功能/新按钮上的内容就是他们所指的内容至。在合并操作期间,这非常简单。

大多数人唯一的问题是重新定案。如果执行重新基准而不是常规合并,则角色将互换。怎么样?好吧,这完全是由重新定基的方式引起的。考虑重新设计工作,像这样:

  1. 自上次拉取以来,您所做的所有提交都移到了自己的分支中,我们将其命名为BranchX。
  2. 您签出当前分支的头,放弃您进行的所有本地更改,但以此方式检索其他人为该分支推送的所有更改。
  3. 现在,BranchX上的每个提交都是精心挑选的,以便从旧到新到当前分支。
  4. BranchX再次被删除,因此永远不会出现在任何历史记录中。

当然,这并不是真正发生的事情,但这对我来说是一个不错的思维模型。如果您查看2和3,您将了解为什么现在要互换角色。从2开始,您当前的分支现在是服务器的分支,无需进行任何更改,因此这是我们的分支(您所在的分支)。您所做的更改现在位于当前分支(BranchX)以外的其他分支上,因此这些更改(尽管是您所做的更改)是它们的更改(您的操作中使用的另一个分支)。

这意味着如果您合并并且希望您的更改始终获胜,则会告诉git始终选择“我们的”,但是如果您重新定基并且希望所有更改都始终获胜,则会告诉git始终选择“他们的”。


Den*_*din 6

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

SCENARIO 1.普通开发者:你是不能合并的开发者,只能master玩feature分支。

案例一:主人为王。您想刷新您的feature分支(= rebase to master),因为master包含依赖项的新更新并且您想覆盖您的适度更改。

git checkout master
git pull

git checkout feature
git rebase -X ours master
Run Code Online (Sandbox Code Playgroud)

案例2:你是国王。您希望将您的feature分支重新设置为master更改的基础。但是你做的比你的同事多,并且想优先使用你自己的改变。

git checkout master
git pull

git checkout feature
git rebase -X theirs master
Run Code Online (Sandbox Code Playgroud)

重要提示:正如您所看到的,正常的开发人员应该喜欢rebase每天早上像练习/咖啡一样重复它。

场景 2. 合并老师:您是团队负责人,想要合并其他分支并将合并的结果直接推送给 master。master是一个你会改变的分支。

案例一:master为王想要合并第三方分支,但是master是一个优先级。feature是你的前辈做的一个分支。

git checkout feature
git pull

git checkout master
git merge -X ours feature
Run Code Online (Sandbox Code Playgroud)

案例二:新改为王当你的资深开发者发布了一个cool feature,你想覆盖master分支中的旧s**t 。

git checkout feature
git pull

git checkout master
git merge -X theirs feature
Run Code Online (Sandbox Code Playgroud)

记住:要在午夜该选记得master是ours始终。并且theirs是feature他们已经完成的。

  • **注意:** `-X` 表示 `--strategy-option` 并允许使用“他们的”或“我们的”中的代码 (3认同)

Ale*_*rie 5

--ours是HEAD且--theirs是REBASE_HEAD, MERGE_HEAD, 或CHERRY_PICK_HEAD. 我发现直接使用提交引用更容易混淆。

变基时:

git restore HEAD thing.js         # use what the current branch has
git restore REBASE_HEAD thing.js  # use what the other branch has
Run Code Online (Sandbox Code Playgroud)

合并时:

git restore HEAD thing.js        # use what the current branch has
git restore MERGE_HEAD thing.js  # use what the other branch has
Run Code Online (Sandbox Code Playgroud)

采摘樱桃时:

git restore HEAD thing.js              # use what the current branch has
git restore CHERRY_PICK_HEAD thing.js  # use what the other branch has
Run Code Online (Sandbox Code Playgroud)