(Git合并) 何时使用'ours'策略,'ours'选项和'theirs'选项?

21

Git合并文档中了解到,递归合并策略只能使用3方合并算法来解决两个分支。当存在多个公共祖先可用于3方合并时,它会创建一个公共祖先的合并树,并将其用作3方合并的参考树。据实际取自Linux 2.6内核开发历史记录的合并提交的测试报告,这种方法可以减少合并冲突而不会导致错误合并。此外,该方法还可以检测和处理涉及重命名的合并。这是拉取或合并一个分支时的默认合并策略。

递归合并策略可以采用以下选项:

作为默认策略的递归合并策略使用3方递归合并算法(在这里Wikipedia上有解释)。

我的理解是,具有冲突块的部分必须手动解决,它们通常呈现为以下形式:

<<<<<<<<<<<
developer 1's code here
============
developer 2's code here
>>>>>>>>>>>

递归合并策略的ours选项文档如下:

此选项通过优先考虑我们的版本来自动清除冲突块。与我们的一面不冲突的其他树更改会反映到合并结果中。对于二进制文件,整个内容都取自我们这一面。

这不应与ours合并策略混淆,后者甚至不看其他树包含什么。它丢弃了其他树所做的一切,声明我们的历史包含了其中发生的所有事情。

假设现在有两个分支Y和M,共同的基础祖先B如下所示:

enter image description here

当使用默认的递归策略合并Y和M时,由于在第30行,Y表示从基本祖先进行的更改而M不是,因此第30行将变为Print("hello");。但是如果我在M分支上运行

git merge -s recursive -X ours Y

合并输出中的第30行是否为Print("bye");

对于那些认为这很明显的人,请注意ours选项所述:

此选项通过优先考虑我们的版本来自动清除冲突块

但是(据我所知)在第30行没有冲突块。

完整起见,我还将给出theirs选项的文档:

这与ours相反。


ours策略的文档如下:

这解决了任意数量的头,但合并的结果树始终是当前分支头的树,有效地忽略了所有其他分支的更改。它旨在用于取代旁路的旧开发历史。请注意,这与recursive合并策略的-Xours选项不同。

因此,返回上面的示例,如果我在M分支上运行:

git merge -s ours Y

很明显,在合并输出中的第30行将是Print("bye");。在这种情况下,为什么也没有一个theirs策略呢?我该如何实现等同于ours策略的相反行为?

我之所以提出这个问题,是因为我正在一个项目中工作,在该项目中,每当开发分支上的代码成功构建时,我都想定期完全覆盖主分支上的更改。这样我就可以确保我的开发分支不会远离主分支太远,并且在主分支上的代码将成功构建。

我看到这个问题 ,它推荐以下解决方案:

git checkout dev-branch
git merge -s ours master

但是 Git 只会输出Already up-to-date,尽管这两个分支包含不同的代码(并且dev-branch实际上比master要领先几个提交)。

我的当前解决方案是执行:

git merge -s recursive -X theirs dev-branch

我也看到了这个问题,它建议使用递归策略theirs选项。 但是由于递归策略ours选项明显不同于我们策略,因此选项的递归策略与我所说的策略也将不同。


这个问题重复了很多其他问题的很多部分。请考虑查看我对 https://dev59.com/51gQ5IYBdhLWcg3w3Xsy、https://dev59.com/P1cP5IYBdhLWcg3wkKpD 和 https://stackoverflow.com/q/44858155/1256452 的回答(也许从最后一个开始看起?)。 - torek
1个回答

9

git merge -s recursive -X ours Y将导致合并后输出的第30行变成Print("bye");吗?

不会,它还会输出Print("hello");。这是因为只有另一边(Y分支)更改了此文件,M分支上的文件版本与其祖先B相同,因此递归合并策略保留了Y分支的更新版本。

您可以尝试:仅当文件版本从M分支与其祖先B不同时(例如更改第30行的提交为Print(“bye1”);),则-X选项可以起作用。现在,如果您使用git merge -s recursive -X ours Y,输出将为Print(“bye1”);

您还可以在您链接的文章的图4中发现,如果文件的一侧与其祖先相同(如第30行和70行),则该文件将保留其他一侧(更改的)版本作为合并结果。

git merge -s ours Y输出Print("bye");的原因:

正如文档所说, 这解决了任意数量的heads,但合并的结果树始终是当前分支head的树,实际上忽略了所有其他分支的更改。

这意味着它将忽略Y分支的版本,并仅保留当前分支的版本。因此,您得到的输出为M分支的版本Print("bye");

-s选项中为什么没有git merge -s theirs

Git仅使用八爪鱼、ours、recursive、resolve和subtree定义了合并策略,因此无法识别-s theirs,这是一个设计问题。关于详细原因,只有Git版本控制系统开发人员可能知道。


对于您的情况(确保development分支覆盖master分支),您可以使用-X theirs选项从development分支中挑选最新提交并将其应用到master分支中:

# On master branch
git cherry-pick development -X theirs

这会完全覆盖“master”分支。
注意:在“git cherry-pick”命令中,“development”表示指向的提交(“development”分支上最新的提交)。您也可以使用提交sha-1值。

为什么有“我们”的策略,却没有“他们”的策略? - UnchartedWaters
Git 只定义了八爪鱼、ours、递归、解决和子树合并策略。这是一个设计问题,只有 Git 版本控制系统的开发人员才可能知道详细原因。 - Marina Liu
你提出的挑选提交(cherry-picking)策略似乎不能产生干净的合并。我仍然收到类似“developmentmaster多 X 个提交,少 Y 个提交”的信息。但无论如何感谢你的帮助。 - UnchartedWaters
如果你想要将开发分支与主分支同步,可以在 cherry-pick 之后使用 git merge development - Marina Liu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接