(Git 合并)何时使用“我们的”策略、“我们的”选项和“他们的”选项?
Posted
技术标签:
【中文标题】(Git 合并)何时使用“我们的”策略、“我们的”选项和“他们的”选项?【英文标题】:(Git Merging) When to use 'ours' strategy, 'ours' option and 'theirs' option? 【发布时间】:2018-01-06 05:59:52 【问题描述】:从git merge documentation 中提取的递归合并策略的定义。
这只能使用 3 路合并算法解决两个头。当有多个共同祖先可用于 3 路合并时,它会创建共同祖先的合并树并将其用作 3 路合并的参考树。据报道,通过对取自 Linux 2.6 内核开发历史的实际合并提交进行的测试,这会导致更少的合并冲突,而不会导致错误合并。此外,这可以检测和处理涉及重命名的合并。这是拉取或合并一个分支时的默认合并策略。
递归策略可以采用以下选项:
如上所述,作为默认策略的递归策略使用 3 路递归合并算法(解释为 here 和 Wikipedia)。
我的理解是,必须手动解决冲突的大块,它们通常是这样表示的
<<<<<<<<<<<
developer 1's code here
============
developer 2's code here
>>>>>>>>>>>
递归合并策略的ours选项记录如下:
此选项通过支持 我们的 版本来强制自动解决冲突的块。与我们这边不冲突的另一棵树的更改会反映到合并结果中。对于二进制文件,全部内容都取自我们这边。
这不应与 ours 合并策略混淆,后者甚至根本不查看其他树包含的内容。它丢弃了其他树所做的一切,并声明我们的历史记录包含其中发生的一切。
现在假设我有两个分支 Y 和 M 的头,它们有一个共同的基础祖先 B,如下所示
当使用默认递归策略合并 Y 和 M 时,第 30 行将变为Print("hello");
,因为在第 30 行,Y 表示从基本祖先的变化,而 M 没有。但是如果我在分支 M 上运行
git merge -s recursive -X ours Y
第 30 行会在合并输出中变为 Print("bye");
吗?
对于那些说这很明显的人,请注意我们的选项声明
此选项强制冲突的帅哥通过支持我们的版本来干净利落地自动解决。
但是(据我所知)第 30 行没有冲突的大块。
为了完整起见,我还将提供他们的选项的文档:
这与我们的相反。
我们的策略的文档如下:
这解决了任意数量的头,但合并的结果树始终是当前分支头的树,有效地忽略了所有其他分支的所有更改。它旨在用于取代分支的旧开发历史。请注意,这与 recursive 合并策略的 -Xours 选项不同。
所以回到上面的例子,如果我跑了
git merge -s ours Y
在分支 M 上,很明显第 30 行将是合并输出中的Print("bye");
。在这种情况下,为什么也没有他们的策略?我怎样才能实现与我们的策略相同和相反的行为?
我问这个问题是因为我正在处理一个项目,只要开发分支上的代码成功构建,我想定期完全用另一个开发分支的更改覆盖主分支。这样我可以确保我的开发分支永远不会偏离主分支太远,并且主分支上的代码将成功构建。
我见过this question推荐的解决方案
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
我还看到了this question,它建议使用 recursive 策略的 theirs 选项。但是,由于 recursive 策略的 ours 选项显然不同于 ours 策略,因此 theirs 选项也是如此递归策略与我所说的他们的策略不同。
【问题讨论】:
这个问题重复了很多其他问题的很多部分。考虑一下我对***.com/q/42099431/1256452***.com/q/44212642/1256452 和***.com/q/44858155/1256452 的回答(也许从最后一个开始?)。 【参考方案1】:
git merge -s recursive -X ours Y
将第 30 行变为Print("bye");
in 合并后的输出?
不,它也会输出Print("hello");
。这是因为只有对方(Y
分支)改变了这个文件,M
分支上的文件版本与他们的祖先B
相同,所以递归合并策略保持更新版本来自Y
分支。
你可以试试:只有来自M
分支的文件版本与他们的祖先B
不同(例如将30行更改为Print(“bye1”);
),然后-X
选项可以工作。现在如果你使用git merge -s recursive -X ours Y
,输出将是Print(“bye1”);
。
您还可以在article you linked的图4中找到,如果文件的一侧与其祖先相同(如第30和70行),则文件将保留另一侧(更改)版本作为合并结果。
git merge -s ours Y
输出原因 Print("bye");:
正如文件所说, 这解决了任意数量的头,但合并的结果树始终是当前分支头的树,有效地忽略所有其他分支的所有更改。
这意味着它将忽略来自Y
分支的版本,并且只保留当前分支的版本。所以你得到的输出是M
分支Print("bye");
的版本。
为什么 -s 选项没有
git merge -s theirs
:
Git 只定义了 octupus、ours、recursive、resolve 和 subtree 的合并策略,因此无法识别-s theirs
,这是设计问题。具体原因,只有git版本控制系统的开发者可能知道。
针对您的情况(确保development
分支覆盖master
分支),您可以cherry-pick
使用-X theirs
从开发分支到主分支的最新提交 strong> 选项:
# On master branch
git cherry-pick development -X theirs
这将完全覆盖master
分支。
注意: git cherry-pick
命令中的development
表示development
分支指向的提交(development
分支上的最新提交)。您也可以改用提交 sha-1 值。
【讨论】:
既然有我们的策略,为什么没有他们的策略? Git 只定义了 octupus、ours、recursive、resolve 和 subtree 合并策略。这是一个设计问题,只有git版本控制系统开发人员可能知道详细原因。 您建议的挑选策略似乎不会导致干净的合并。我仍然收到“development
是 X 提前提交,Y 提交落后 master
”形式的消息。不过还是谢谢你的帮助。
如果你想开发和master同步,你可以在cherry-pick之后使用git merge development
。以上是关于(Git 合并)何时使用“我们的”策略、“我们的”选项和“他们的”选项?的主要内容,如果未能解决你的问题,请参考以下文章
Git:在 gitattribute 中为整个文件夹指定一个 git 合并策略“我们的”(或者只是禁用特定文件夹上的合并错误?)