如何让git在解决合并冲突时先采用"我们的版本,然后是他们的版本"的方式?

3
我希望能够通过将“我们的”块放在前面,然后是“他们的”块来自动解决“两个分支在同一行添加块”的冲突。
因此,与其出现如下冲突:
```html <<<<<<< HEAD ours ======= theirs >>>>>>> branch-a ```
我们可以得到以下结果:
```html <<<<<<< HEAD ours >>>>>>> branch-a theirs ```
16:09:44 tims@firebat ~/git/merge_conflict_example (master|MERGING) $ cat test.txt
good morning
good evening
<<<<<<< HEAD
g'day
=======
aloha
>>>>>>> branch1
hello
hi

我只是获取:

16:09:44 tims@firebat ~/git/merge_conflict_example (master) $ cat test.txt
good morning
good evening
g'day
aloha
hello
hi

没有冲突。

我想可能会有类似于git merge branch1 -X oursthentheirs的东西。

我在这里使用的示例可在git@bitbucket.org:abznak/merge_conflict_example.git中找到。

3个回答

2

虽然没有内置的功能,但是如果你将merge.conflictstyle设置为diff3,那么编写一个程序(可以使用perl或python,或者我可以用awk编写一个简单版本)来检查“原始”部分是否为空——这将检测到“双方都添加”的情况——如果是空的,就可以简单地删除冲突标记:

good morning
good evening
<<<<<<< HEAD
g'day
|||||||
=======
aloha
>>>>>>> branch1
hello
hi

这是我的awk脚本(我不敢说它很好,但它适用于样例输入)。请注意,它不能很好地处理“嵌套冲突”(即,如果两个原始有冲突的文件包含看起来像是冲突标记的内容,这将出错)。

BEGIN { in_conflict = retained_left = retained_mid = retained_right = 0 }
function handle_retained(is_eof) {
        # If the section between ||||||| and ======= is empty,
        # retained_mid+1 == retained_right.  Otherwise print
        # all the retained conflict lines.
        if (retained_mid + 1 == retained_right) {
                s1 = retained_left + 1  # after <<<<<<<
                e1 = retained_mid - 1   # before |||||||
                s2 = retained_right + 1 # after =======
                e2 = NR - 1             # before >>>>>>>
        } else {
                s1 = retained_left; e1 = NR
                s2 = 1; e2 = 0
        }
        for (i = s1; i <= e1; i++)
                print retained[i]
        for (i = s2; i <= e2; i++)
                print retained[i]
        delete retained
        if (is_eof) {
                # this should never happen!
                print "WARNING: ended input while still in conflict marker"
                exit(1)
        }
}
/^<<<<<<</ { in_conflict = 1; retained_left = NR }
{
        if (!in_conflict)
                print
        else
                retained[NR] = $0
}
/^\|\|\|\|\|\|\|/ { if (in_conflict) retained_mid = NR }
/^=======/ { if (in_conflict) retained_right = NR }
/^>>>>>>>/ { if (in_conflict) handle_retained(0); in_conflict = 0 }
END { if (in_conflict) handle_retained(1) }

1
嗯,awk看起来肯定很有趣。加一分给那个混乱... :D (还有努力) - poke
我应该为那些不熟悉awk的人添加一些注释:NR是当前输入行的“记录”(行)号,从1开始计数所有输入行。形式为/pattern/ { action }的行执行给定的操作,缺少/pattern/时总是执行;这些按顺序执行,因此我们首先检查7个<,然后进行打印或保留,然后在每行上检查7-|等。 - torek

1
很容易,只需将 merge git 属性设置为 union 即可。来自 https://git-scm.com/docs/gitattributes

union

对于文本文件运行三方文件级合并,但是从两个版本中获取行,而不是留下冲突标记。这往往会使得结果文件中添加的行处于随机顺序,用户应该验证结果。如果您不理解影响,请勿使用此选项。

例如,我刚刚添加了一个包含文本 *.txt merge=union 的 .gitattributes 文件:
10:58:21 tims@thor ~/git/merge_conflict_example (master) $ cat .gitattributes
*.txt merge=union

并运行了合并:

10:58:26 tims@thor ~/git/merge_conflict_example (master) $ git merge origin/branch1
Auto-merging test.txt
[...]
Merge made by the 'recursive' strategy.
 test.txt | 1 +
 1 file changed, 1 insertion(+)

这产生了预期的效果:

10:58:42 tims@thor ~/git/merge_conflict_example (master) $  cat test.txt 
good morning
good evening
g'day
aloha
hello
hi

当我在寻找一种方法让git自动运行@torek的解决方案时,我偶然发现了这个答案。 - Tim Smith

0

您可以使用“ours”合并策略将分支old合并到当前分支中,命令如下:

$ git merge -s ours old


1
使用“ours”策略合并会完全丢弃另一个树的更改,这不是OP想要的。使用“ours”修饰符合并到“递归”策略(-X ours)也会丢弃另一个树的更改,但仅在冲突的情况下。这会保留一些其他树的更改,但不包括任何冲突的添加 - 所以这仍然不是OP要求的。 - torek

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