(Git合并)何时使用“我们的"策略,“我们的"选项和“他们的"选项? [英] (Git Merging) When to use 'ours' strategy, 'ours' option and 'theirs' option?

查看:108
本文介绍了(Git合并)何时使用“我们的"策略,“我们的"选项和“他们的"选项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

git合并文档中提取的递归合并策略的定义.

这只能使用3向合并算法解析两个磁头.当有一个以上的公共祖先可用于三向合并时,它将创建一个公共祖先的合并树,并将其用作三向合并的参考树.据报道,通过对来自Linux 2.6内核开发历史记录的实际合并提交进行的测试,可以减少合并冲突,而不会引起合并错误.此外,这可以检测和处理涉及重命名的合并.这是拉出或合并一个分支时的默认合并策略.

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

如上所述,递归策略是默认策略,它使用三向递归合并算法(解释为,因为在第30行,Y表示从基本祖先开始的更改,而M则不是.但是如果我在M分支上并运行

git merge -s recursive -X ours Y

第30行在合并后的输出中会变成Print("bye");吗?

对于那些说这很明显的人,请注意我们的选项指出

此选项通过支持 our 版本来强制自动解决冲突的帅哥.

但是(据我所知),第30行没有冲突的块.

为完整起见,我还将提供选项的文档:

这与我们的相反.


我们的策略的文档如下:

这可以解析任意数量的head,但是合并的结果树始终是当前分支head的树,从而有效地忽略了所有其他分支的所有更改.它旨在取代侧支的旧开发历史.请注意,这与递归合并策略的-Xours选项不同.

如果我跑了,回到上面的例子

git merge -s ours Y

在分支M上的

上,很明显,合并后的输出中的第30行是Print("bye");.在这种情况下,为什么还没有他们的策略?如何实现与我们的策略相同和相反的行为?

之所以问,是因为我正在开发一个项目,无论何时成功构建开发分支上的代码,我都想用另一个开发分支上的更改定期并完全覆盖master分支.这样,我可以确保开发分支永远不会偏离master分支,并且确保master分支上的代码将成功构建.

我看过这个问题建议使用递归策略的选项.但是,由于递归策略的我们的选项与我们的策略明显不同,因此, 递归策略与我所说的他们的策略不同.

解决方案

git merge -s recursive -X ours Y将第30行变成 合并的输出?

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

您可以尝试:只有M分支中的文件版本不同于其祖先B(例如,将30行更改为Print(bye1);的提交),然后-X选项才可以使用.现在,如果您使用git merge -s recursive -X ours Y,则输出将为Print(bye1);.

您还可以在

如文件所述, 这可以解析任意数量的head,但是合并的结果树始终是当前分支head的树,有效地忽略了所有其他分支的所有更改.

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

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

Git仅使用 octupus 我们的递归解决子树定义了合并策略,因此-s theirs无法识别,这是一个设计问题.出于详细原因,只有git版本控制系统开发人员可能知道.


根据您的情况(确保development分支覆盖master分支),您可以使用 -X theirs cherry-pick 从开发分支到主分支的最新提交 strong>选项:

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

这将完全覆盖master分支.

注意: git cherry-pick命令中的development表示development分支指向的提交(development分支上的最新提交).您也可以改用commit sha-1值.

Definition of recursive merge strategy pulled from the git merge documentation.

This can only resolve two heads using a 3-way merge algorithm. When there is more than one common ancestor that can be used for 3-way merge, it creates a merged tree of the common ancestors and uses that as the reference tree for the 3-way merge. This has been reported to result in fewer merge conflicts without causing mismerges by tests done on actual merge commits taken from Linux 2.6 kernel development history. Additionally this can detect and handle merges involving renames. This is the default merge strategy when pulling or merging one branch.

The recursive strategy can take the following options:

As stated, the recursive strategy, which is the default strategy, makes use of the 3-way recursive merge algorithm (explained here and on Wikipedia).

My understanding is that conflicting hunks must be manually resolved and they are typically represented like this

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

The ours option of the recursive merge strategy is documented as follows:

This option forces conflicting hunks to be auto-resolved cleanly by favoring our version. Changes from the other tree that do not conflict with our side are reflected to the merge result. For a binary file, the entire contents are taken from our side.

This should not be confused with the ours merge strategy, which does not even look at what the other tree contains at all. It discards everything the other tree did, declaring our history contains all that happened in it.

Now suppose I have the heads of two branches Y and M, with a common base ancestor B as follows

When merging Y and M using the default recursive strategy, line 30 will become Print("hello"); since at line 30, Y represents a change from the base ancestor and M does not. But if I were on branch M and run

git merge -s recursive -X ours Y

will line 30 become Print("bye"); in the merged output?

To those of you who say that this is obvious, note that the ours option states

This option forces conflicting hunks to be auto-resolved cleanly by favoring our version.

But (as I understand) there is no conflicting hunk at line 30.

For completeness, I will also give the documentation of the theirs option:

This is the opposite of ours.


The documentation for the ours strategy is as follows:

This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches. It is meant to be used to supersede old development history of side branches. Note that this is different from the -Xours option to the recursive merge strategy.

So returning to the example above, if I ran

git merge -s ours Y

on branch M, it is clear that line 30 will be Print("bye"); in the merged output. In this case, why is there also not a theirs strategy? How can I achieve behaviour equal and opposite to the ours strategy?

I'm asking because I'm working on a project where I want to regularly and completely overwrite the master branch with changes from another development branch, whenever the code on the development branch builds successfully. This way I can ensure that my development branch never drifts too far off from the master branch and also that the code on the master branch will build successfully.

I have seen this question which recommends the solution

git checkout dev-branch
git merge -s ours master

But Git simply outputs Already up-to-date, despite the fact that the two branches contain different code (and dev-branch is actually a few commits ahead of master).

My current solution is to do

git merge -s recursive -X theirs dev-branch

I have also seen this question which recommends using the theirs option of the recursive strategy. But as the ours option of the recursive strategy is clearly different ours strategy, so too would the theirs option of the recursive strategy be different from the theirs strategy that I'm talking about.

解决方案

git merge -s recursive -X ours Y will line 30 become Print("bye"); in the merged output?

No, it will also output Print("hello");. This is because only the other side (Y branch) changed this file, file version on M branch is the same as their ancestor B, so recursive merge strategy keep the updated version from Y branch.

And you can have try: only the file’s version from M branch is different from their ancestor B (such as commit for changing 30 line as Print("bye1");), then the -X options can works. Now if you use git merge -s recursive -X ours Y, the output will be Print("bye1");.

And you can also find in Figure 4 of the article you linked, if one side of the file is same as their ancestor (as line 30 and 70), the file will keep the other side (changed) version as the merge results.

Reason for git merge -s ours Y output Print("bye");:

As the document said, This resolves any number of heads, but the resulting tree of the merge is always that of the current branch head, effectively ignoring all changes from all other branches.

That means it will ignore the version from Y branch and only keep the version as current branch is. So you got the output as the version of M branch Print("bye");.

Why there is no git merge -s theirs for -s option:

Git only defined the merge strategies with octupus, ours, recursive, resolve and subtree, so the -s theirs can’t be recognized and it’s a design issue. For the detail reason, only the git version control system developers may know.


For your situation (make sure development branch overwrite master branch), you can cherry-pick the latest commit from development branch to master branch with -X theirs option:

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

This will fully overwrite master branch.

Note: development in git cherry-pick command means the commit which development branch is point to (latest commit on development branch). You can also use commit sha-1 value instead.

这篇关于(Git合并)何时使用“我们的"策略,“我们的"选项和“他们的"选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆