Git何时会成功合并与冲突?

时间:2019-06-19 17:11:13

标签: git

如果我有一个新的干净项目(主文件),并且添加了一个包含以下内容的新文件:

Master:test.txt

"123"

现在,我正在创建一个名为“ MyBranch”的新的分支分支,然后更改文件的内容:

MyBranch:test.txt

"193"

现在我要合并Mybranch --> Master

在这种情况下,我不知道这将是成功的合并还是冲突。 我已经看到了冲突和成功合并但仍然找不到黄金法则的情况。

问题

git什么时候引发冲突与成功合并?

3 个答案:

答案 0 :(得分:3)

当在同一代码段的不同分支上进行两次编辑时,

git引发冲突。

根据您的情况,由于您仅在Mybranch中进行了一次编辑,因此合并时不会出现冲突。

如果在Master上进行了一次新的提交,在我尝试将其合并之前,我将文本更改为“ 987” 并提交了该代码,那么我们将发生冲突。

有用的资源:https://www.atlassian.com/git/tutorials/using-branches/git-merge

答案 1 :(得分:2)

总的来说,当具有两个具有相同共同祖先的分支,并且每个分支对于给定数量的行具有一组不同的更改时,就会发生冲突。

所以....如果您有一个共同的祖先A,则分支B和C并从A到B从文件中删除了5行...并且在A和C之间您修改了这5行中的任何一条,您会发生冲突。有许多种冲突。一种方式修改5行,另一种方式修改相同的5行..您合并,繁荣!还有其他类型的冲突,例如:在一个文件上编辑5行...在另一分支上删除文件。合并:繁荣!

如果一个分支上有一组更改,而另一个分支上没有更改,则不会有冲突。

答案 2 :(得分:1)

eftshift0 says一样,尽管用不同的词表示,但这里的窍门是合并中没有两个输入,但有三个输入。

您将过程描述为:

  • master上创建新的提交
  • 创建新分支MyBranch
  • MyBranch上创建新的提交
  • 运行:

    git checkout master
    git merge MyBranch
    

但这并不是发展的趋势。通常更像是:创建三个分支,开始对其进行创建,再创建六个,对其中一些进行处理,删除其中一些,创建其他,对其中几个进行一段时间,然后最终检查出并运行git merge上的另一个。这种更加混乱的工作流程导致对合并过程的输入更加复杂,正如我上面提到的那样,它实际上由三个提交组成。

在这三个提交中,仅选择了两个。第三个,Git自动为您选择。

让我们花点时间回顾一下使用图纸创建新提交的过程。您:

git checkout somebranch
<edit various files>
git add <some edited files>
git commit

checkout步骤会填充索引(或多或少提议的下一个提交)以及工作树,其中包含位于分支{当前 tip 处的所有提交文件{1}}:

somebranch

(每个字母代表一个实际的提交哈希ID)。最新提交...--F--G--H <-- somebranch 的父级是提交HG的父级是G,依此类推,在分支上“上”(包含在其中)的提交行向下。

编辑文件时,将更改工作树副本。然后,您必须F将那些更改复制回索引中— git add使用索引(建议的提交,文件处于特殊的经过Git冻结的状态),而不是工作树(正常的日常文件格式,可由常规的非Git程序使用)。最后一步,git commit,打包所有文件的索引副本,不仅是您更改过的文件,还包括其中所有 all 未更改文件的索引副本由于提交git commit而建立索引,并将它们存储到新的提交中,并在其中冻结所有时间,以便将来任何时候都可以返回到新的提交。

我们将此新提交称为HI的父母将是I

H

...--F--G--H <-- somebranch \ I last 步骤是更新名称 git commit,以使其指向提交somebranch而不是提交I

H

(而且我们不再需要图形中的扭结)。

因此,在您的特定过程中,您选择的分支为...--F--G--H--I <-- somebranch ,并添加了新的提交:

master

然后您创建了一个新的分支 name 。默认情况下,这个新名称​​还指向提交...--F--G--H--I <-- master 。通过I进行的提交现在位于两个分支中(包含在两个分支中):

I

现在,我们的图纸需要再添加一项。 Git如何知道在这里使用哪个分支 name ?答案是,Git在所有这样的大写字母中将特殊名称...--F--G--H--I <-- master, MyBranch 附加到分支名称之一。当HEADgit status说到on branch master时,这就是您所在的分支。假设您创建并进入on branch MyBranch,以便拥有:

MyBranch

现在,您创建另一个新的提交。这会得到一个很大的难看的哈希ID,但我们将其称为...--F--G--H--I <-- master, MyBranch (HEAD) 。和以前一样,Git将根据索引中的内容进行新的提交,因此您可以编辑文件,J将它们复制回索引中,然后git add进行git commit:< / p>

J

(请注意,...--F--G--H--I <-- master \ J <-- MyBranch (HEAD) 仍附加到更新的分支。)

现在可以运行HEAD 了,但是这种合并不是很有趣。太琐碎了。这里永远不会有任何合并冲突。实际上,默认情况下,git checkout master; git merge Mybranch会注意到不需要合并,而是执行快进。您必须运行git merge来强制它进行真正的合并(该合并会很好)。

首先,让我们在git merge --no-ff上进行一次新提交,而不是立即进行合并。实际上,只是为了使合并得到字母master,我们在M上进行两次提交,所以我们有:

master

现在,当我们运行 K--L <-- master (HEAD) / ...--F--G--H--I \ J <-- MyBranch 时,Git必须做一些实际的工作。

第一部分在于查找三个输入提交:

  • 这三个提交之一是您当前正在执行的提交-提交git merge MyBranchLmaster(两个名称,再加上原始哈希ID) ,选择该特定的提交)。该特定提交的文件将位于您的索引和工作树中,而索引或工作树中没有任何更改(HEAD会检查这种情况,并且通常不会让您使用“脏”索引或工作树)。

  • 这三项之一是您命名的提交:在git merge中,您已将提交命名为git merge MyBranch

  • 最后一个提交-您没有选择的提交-是Git所说的合并基础,它是共同的起点两个分支分歧。由于我们一直在绘制这些内容,因此很容易看到哪个提交:它是提交J

    当我们从提交I开始并向后工作时(如Git所做的那样),我们先列举提交L,然后依次是L,然后依次是K和{{1} }, 等等。同时,当我们从提交I开始并向后工作时,我们先列举提交H,然后依次依次是JJ,等等。

    共享提交是IHIH等,但是 best 共享提交是最后,或提交G。因此,提交F是合并的基础。

现在I找到了三个输入,它的主要工作开始了:

  • 比较提交I(或其中的快照)以提交git merge的快照。这里有什么不同,是我们在I上更改了我们的内容:

    L
  • 比较提交master与提交git diff --find-renames <hash-of-I> <hash-of-L> 。这里有什么不同,是在I上更改了他们(好,“我们”)的内容:

    J
  • 组合这两个比较的结果。

  • 将合并的更改应用于提交MyBranch中的快照。

如果一切顺利,则合并的更改(将快照从git diff --find-renames <hash-of-I> <hash-of-J> 捕获到I的那些,加上将快照从I捕获到L的那些,现在已合并在每个文件的索引副本和工作树副本中,I提交结果,就像通过J一样,但进行的提交同时记住两者 {{1} } git merge

git commit

并没有直接记录合并使用的提交L的事实,但这是隐含的:提交J K--L / \ ...--F--G--H--I M <-- master (HEAD) \ ___/ J <-- MyBranch 的合并基础为I,并且始终会永远都是这样,因为任何提交中的每一个信息都一直冻结。例如,事实是L的父母是J,而I的父母是L:这些事实不能更改。 K的父母现在分别为KI,无法更改。任何提交的任何部分都永远无法更改:至多,我们可以做出新的和改进的(和不同的)提交,只是停止使用旧的提交,但是我们不能更改旧的提交。

进展顺利时,您会遇到合并冲突。例如,如果从ML的差异表示要将文件J的第10行从I更改为J,而差异从{{1 }}到test.txt表示要将文件ABC的第10行从XYZ更改为I,这些更改会发生冲突。 Git将:

  • 所有三个输入文件保留在索引中(在特殊的高编号登台插槽中,我们将不在此处介绍),并且
  • 在工作树中留下文件的混乱,合并冲突版本,您可以在其中查看和使用它。

合并没有结束,但也没有完成。现在,合并未完成的事实记录在两个地方:

  • 在索引中,因为占用了非零的登台时隙;和
  • 包含提交L的哈希ID的文件中,以便最终的合并“进行提交”步骤知道要包含哪个哈希ID作为另一个父ID。 (第一个父级test.txt哈希ID始终可以通过ABC获得。)

您的工作将变为:为此文件生成正确的组合,并将其写入staging-slot-zero处的索引中,以声明该文件已解决AEIOU命令将处理第二部分(写索引),但是您必须自己提出正确的 content 或借助合并工具

解决所有冲突后,请运行:

J

或:

L

在这种情况下两者都做相同的事情:HEAD确保有一个正在进行的合并可以完成,如果是这样,实际上只是运行git add(无论如何,现在-适用于Windows的Git用户一直将一个命令粘贴在另一个命令中,而不是运行另一个命令,因为Windows显然要花几个小时…...好吗,十分之几秒?...才能将一个命令链接到另一个命令,而不是Linux上的微秒)。