git合并冲突究竟何时发生 [英] when exactly does a git merge conflict arise

查看:31
本文介绍了git合并冲突究竟何时发生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 git 来跟踪对 LaTeX 文档的更改.我倾向于将共同作者的反馈保留在一个单独的分支中,然后再合并.到目前为止,事情似乎神奇地正确合并,但我想知道合并冲突究竟何时发生,以便我可以在合并过程中获得一些真正的信任(我当然不希望文本变得时髦).

I'm using git to track changes to my LaTeX documents. I tend to keep feedback from co-authors in a separate branch and merge it in later. So far things seem to magically merge properly, but I would like to know when exactly a merge conflict occurs, so that I can obtain some real trust in the merging process (I would not like text to come out funky of course).

StackOverflow 上有很多问题似乎都在问同样的问题,但没有一个答案非常具体.例如 this answer 指定如果对同一区域进行更改会发生冲突,但这让我想知道究竟是什么这些地区是.只是对同一行进行了更改,还是考虑了某些上下文?

There are a number of questions on StackOverflow that seem to ask the same thing, but none of the answers get very specific. For example this answer that specifies that a conflict occurs if changes were made to the same region, but that makes me wonder what exactly those regions are. Is it just changes made to the same line, or is some context taken into account?

推荐答案

它是一行一行的,答案是否"和是":上下文确实很重要,但重要的数量是棘手的.它比您最初想象的要多或少.

It's on a line by line basis, and the answer is sort of both no and yes: context does matter, but the amount that it matters is tricky. It's both more and less than you might think at first.

您可能想先浏览此答案以了解相关问题的背景知识.我现在假设我们有 base 作为(单个)合并基础(也许我们通过标记特定的提交来设置名称 base,例如,git tag base$(git merge-base HEAD other)) 和 HEAD 作为我们在分支 b1 上的提交,还有一些其他的分支名称b2 命名另一个提交.

You might want to skim through this answer to a related question first, for background. I will now assume that we have base as the (single) merge base (perhaps we set the name base by tagging the specific commit, e.g., git tag base $(git merge-base HEAD other)) and HEAD as our commit on branch b1, with some other branch-name b2 naming the other commit.

接下来,我们看看两个差异:

Next, we look at the two diffs:

git diff base HEAD
git diff base b2

如果我们看到文件 F 的所有三个版本都不同(因此 F 出现在两个输出中,并且更改不同),那么我们必须工作,在本质上,差异大块一个差异大块.在差异块重叠但进行不同更改的地方,Git 声明冲突.但是——这似乎是你的问题——做出不同的改变"究竟是什么意思?

If we see that all three versions of file F are different (so that F appears in both outputs, and the changes differ), we must then work, in essence, diff-hunk-by-diff-hunk. Where diff hunks overlap, but make different changes, Git declares a conflict. But—this seems to be your question—what, exactly, does "make different changes" mean?

我认为这是最好的例子.例如:

I think this is best shown by example. For instance:

$ git checkout b1
[checkout messages here - but I was already on b1]
$ git diff base HEAD
diff --git a/basefile b/basefile
index df781c1..e4f9e4b 100644
--- a/basefile
+++ b/basefile
@@ -4,6 +4,7 @@
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
+# added line in b1
 # 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright

和:

$ git diff base b2
diff --git a/basefile b/basefile
index df781c1..c96620e 100644
--- a/basefile
+++ b/basefile
@@ -4,7 +4,6 @@
 # Redistribution and use in source and binary forms, with or without
 # modification, are permitted provided that the following conditions
 # are met:
-# 1. Redistributions of source code must retain the above copyright
 #    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the

请注意,虽然这些更改不会触及同一行,但在某种意义上,它们也确实触及同一行.我添加了第 7 行(将旧的第 7 行推到第 8 行),并删除了旧的第 7 行.显然,这些是相同"的行.所以:

Note that while these changes don't touch the same line, in a sense, they also do touch the same line, in a sense. I added a line 7 (pushing old line 7 down to line 8), and I deleted the old line 7. These are, apparently, the "same" line. So:

$ git merge b2
Auto-merging basefile
CONFLICT (content): Merge conflict in basefile
Automatic merge failed; fix conflicts and then commit the result.

让我们中止这次合并并考虑分支b3的尖端(b1b3的合并基础与合并相同b1b2 的基础,在我的设置中).

Let's abort this merge and consider the tip of branch b3 instead (the merge base of b1 and b3 are the same as the merge base of b1 and b2, in my setup).

$ git merge --abort
$ git diff base b3
diff --git a/basefile b/basefile
index df781c1..e2b8567 100644
--- a/basefile
+++ b/basefile
@@ -5,7 +5,6 @@
 # modification, are permitted provided that the following conditions
 # are met:
 # 1. Redistributions of source code must retain the above copyright
-#    notice, this list of conditions and the following disclaimer.
 # 2. Redistributions in binary form must reproduce the above copyright
 #    notice, this list of conditions and the following disclaimer in the
 #    documentation and/or other materials provided with the distribution.
 $ git merge --no-edit b3
Auto-merging basefile
Merge made by the 'recursive' strategy.
 basefile | 1 -
 1 file changed, 1 deletion(-)

这一次没有冲突,即使两个差异大块都接触到了相同的区域.第二个 diff 删除了没有触及"添加行的行,因此 Git 认为这是安全的.

This time there was no conflict, even though both diff hunks touched the same general area. The second diff deleted a line that was not "touching" the added line, so Git considered this safe.

如果您以同样的方式进行更多实验,您会准确地发现哪些看似重叠的更改成功组合,哪些会导致冲突.显然,直接重叠的更改,例如,删除原始行 42 并插入不同的新行 42,将发生冲突.但是所有更改始终表示为删除一些现有行,尽管可能为零",然后是添加一些新行,但可能为零".更改——即使只是更改、添加或删除一行中的一个单词——会删除非零数量的现有行并添加非零数量的新行.纯删除(一个或多个完整行)添加 零行,纯插入删除 零行.最后,它归结为:我们和他们的更改是否涉及相同的行号?"上下文变得几乎无关紧要,除了在删除零行或插入零行时,上下文本身在某种意义上就是"行.(我不确定这个说法有多大意义,所以如果它难以理解,那是我的错.;-))

If you experiment more, in this same fashion, you will find exactly which seemingly-overlapping changes are combined successfully, and which result in a conflict. Obviously changes that directly overlap, e.g., where both delete original line 42 and insert a different new line 42, will conflict. But all changes are always represented as "delete some existing line(s), though maybe zero of them" followed by "add some new line(s), though maybe zero of them". A change—even one that changes, adds, or deletes just one word within a line—deletes a nonzero number of existing lines and adds a nonzero number of new lines. A pure-delete (of one or more complete line) adds zero lines, and a pure-insert deletes zero lines. In the end, it comes down to: "Did both ours-and-theirs changes touch the same line number?" The context becomes almost irrelevant, except that when deleting zero lines, or inserting zero lines, the context itself "is" the lines, in a sense. (I'm not sure how much sense this claim makes, so if it's incomprehensible, that's my fault. ;-) )

(还请记住,如果您在工作时修改到目前为止已合并"的文件,则在查看更改是否触及相同"时必须使用原始基本文件的行号行.因为我们的"和他们的"都有相同的基础版本,这是我们可以在这里使用的一个简单的捷径.)

(Remember also that if you are modifying the "merged so far" file as you work, you must use the original base-file's line numbers when looking at whether a change touched "the same" lines. Since both "ours" and "theirs" have the same base version, that's an easy short-cut we can use here.)

请注意,这与应用 补丁 不同,后者无需通用基础版本即可启动.在补丁的情况下,上下文被更多地使用:diff 块头提供了搜索上下文的位置,但由于它可能应用于文件的不同版本,上下文允许我们(和 Git)在不同的行进行相同的更改,只要上下文仍然匹配.

Note that this differs from applying a patch, which is done without a common base version to start. In the case of a patch, the context is used much more heavily: the diff hunk header provides the location for searching for the context, but since it might be applied to a different version of the file, the context allows us (and Git) to make the same change at a different line, as long as the context still matches.

patch 实用程序在这里使用不同的算法(最大模糊"因子,看起来 +/- 那么多行).Git 不做模糊因素;如果必须,它将一直搜索到文件的开头或结尾.但是,在确定上下文无法匹配之前,它确实有调整空白的常用选项.

The patch utility uses a different algorithm here (a "maximum fuzz" factor, looking +/- that many lines). Git doesn't do fuzz factors; it will search all the way to the beginning or end of the file, if it has to. It does, however, have the usual option of tweaking white space before deciding that context fails to match.

(使用git apply打补丁时,可以添加-3--3way让Git读取index 行,提供文件 blob 的部分或完整哈希 ID.左边的哈希 ID 是文件先前版本的哈希:请注意,在上面的所有差异中,基本"版本的basefile 有 ID df781c1.如果 Git 可以从该 ID 中找到唯一的 blob,它可以假装这是合并基,并且只针对一个合并基进行区分HEAD,将补丁本身视为 other 差异,并以这种方式进行三向合并.这有时允许 git apply 在以下情况下成功patch 会失败.)

(When using git apply to apply a patch, you can add -3 or --3way to allow Git to read the index lines, which provide partial or full hash IDs of file blobs. The left hand hash ID is the hash of the previous version of the file: note that in all the diffs above, the "base" version of basefile has ID df781c1. If Git can find a unique blob from that ID, it can pretend that that is the merge-base, and diff just the one merge-base against HEAD, treating the patch itself as the other diff, and do a three-way merge that way. This sometimes allows git apply to succeed where patch would fail.)

这篇关于git合并冲突究竟何时发生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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