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

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

问题描述

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

git merge -s recursive -X ours Y

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

对于那些认为这很明显的人,请注意我们的选项声明

<块引用>

此选项强制冲突的帅哥通过偏爱我们的版本来自动解决.

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

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

<块引用>

这与我们的相反.


我们的策略的文档如下:

<块引用>

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

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

git merge -s 我们的 Y

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

我之所以这么问是因为我正在处理一个项目,只要开发分支上的代码成功构建,我就希望定期完全覆盖主分支,并使用另一个开发分支的更改.这样我就可以确保我的开发分支永远不会偏离主分支太远,并且主分支上的代码将成功构建.

我见过 这个问题 推荐解决方案

git checkout dev-branchgit merge -s 我们的主人

但 Git 只是简单地输出 Already up-to-date,尽管事实上这两个分支包含不同的代码(而且 dev-branch 实际上比master).

我目前的解决方案是做

git merge -s recursive -X theirs dev-branch

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

解决方案

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");.

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

<块引用>

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

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

这意味着它将忽略来自 Y 分支的版本,只保留当前分支的版本.所以你得到的输出是 M 分支 Print("bye");.

<块引用>

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

Git 只定义了八爪鱼我们的递归解析子树的合并策略,所以 -s theirs 不能被识别,这是一个设计问题.具体原因可能只有git版本控制系统开发者知道.

<小时>

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

# 在 master 分支上git cherry-pick 开发 -X 他们的

这将完全覆盖 master 分支.

注意: git cherry-pick 命令中的 development 表示 development 分支指向的提交(development 分支上的最新提交).您也可以改用提交 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 Merging) 何时使用“我们的"策略、“我们的"选项和“他们的"选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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