对,所以我搜索了其他一些SO线程,并还检查了这个:https://git-scm.com/docs/git-merge
我了解--allow-unrelated-histories允许两个项目结合在一起,但是,我不了解的是它的工作原理。
它像这样工作吗? https://imgur.com/a/ZFVVs7s
上面的git站点显示此图:
A---B---C topic
/ \
D---E---F---G---H master
但是,在我看来,它们似乎没有无关的历史记录,因为主题分支从'E'中分离出来了。即使主题分支从“ D”的母版中分离出来,他们仍然会共享“ D”分支。
任何人都能够(最好是用视觉效果)解释允许无关历史如何工作吗?我正在尝试git pull,但是我的团队成员之一编辑了我要从中拉出的分支,现在我必须使用--allow-unrelated-histories。
谢谢!
答案 0 :(得分:4)
您是正确的,您的图表(来自git-scm.com/docs/git-merge)显示了具有共同祖先提交的合并。值得注意的是,这是一个共享的 commit; 术语 branch 在Git中有点棘手。 (请参见What exactly do we mean by "branch"?)
无论如何,如果您忘记了git pull
的存在,我认为这会有所帮助。 git pull
所做的全部工作就是为您运行两个不同的Git命令。除非您对Git有足够的经验,否则最好使用单独的git fetch
和git merge
命令。 (请注意,git pull --rebase
将第二个命令切换为git rebase
,但在此不做详细介绍。)使用git pull
运行其他两个命令存在多个问题。其中之一是git pull
使用怪异的pull-only语法,与 all 其他Git命令不同,包括运行git merge
的{{1}}。也就是说,您将运行git pull
而不是git pull origin xyz
。要查看其含义,请运行git merge origin/xyz
或git log origin/xyz
等。它们总是用斜杠拼写为git show origin/xyz
,但使用origin/xyz
时除外,所以不要不要使用git pull
。 :-)让我们将其分为两个单独的命令。
git pull
运行的第一个命令是git pull
,您可以随时运行它:git fetch
调用其他Git,询问它对您有什么承诺,使用什么名称(通常是分支名称和标记名称)。它收集这些提交(当然还有它们的文件),并为每个其分支名称创建或更新您的远程跟踪名称。这样就是git fetch
的来源,例如:origin/master
看到他们有一个git fetch
,他们的主人正在提交master
或其他任何东西,并创建或更新了{{ 1}}要记住: badf00d
的主人是我上次检查的origin/master
。
origin
为您运行的第二个命令是所有有趣的操作所在。第二条命令不应在任何旧时间在任何旧分支上运行,因为无论您运行了Git的第二条命令,都必须在 right 分支上运行:您要合并到其中的一个,或您要重新设定基准的一个。我发现在这里使用单独的命令会有帮助,因为很明显badf00d
会影响 current 分支,即使您将命名为git pull
之类。
现在我们知道git merge
确实是origin/master
的一种选择,让我们深入研究--allow-unrelated-histories
,然后看看它的作用。首先,我们将看看它在 的共同出发点,然后再来看它在没有的情况下进行的工作。
考虑一下上面引用的图,我将重画一下:
git merge
这表示无论谁在git merge
上工作,他们都是从签出提交 A--B--C <-- topic
/
D--E--F--G <-- master (HEAD)
开始的。当时,提交topic
可能是对{em> E
的最后一次提交:
E
此后,有人在master
上添加了两个提交,分别是D--E <-- master, topic
和master
,有人(可能是其他人)在F
上添加了三个提交,分别是现在是G
链(topic
的父提交为A-B-C
)。
每个提交代表所有源文件的完整快照。因此,提交A
包含其中的所有文件-以及,当您或任何人进行提交E
时拥有的所有文件-永远保存为这种形式。您或该人从该已保存状态对任何文件进行的任何更改(例如,提交E
)都会导致这些文件在E
中处于新状态。 A
中任何未更改文件都与A
中的文件完全匹配。
为简单起见,我们假设有两个人在这里行事,“ you”和“ they”,并且您在A
上进行了更改,最终导致了E
的提交。然后,他们从master
到G
。因此,您和他们俩都从永久保存在提交A
中的所有内容开始。您将得到永久保存在C
中的内容。因此,Git可以通过简单的E
找出您所做的更改,以比较提交G
与提交git diff
。同样,它们最终以E
结尾,因此Git可以通过比较G
与C
来找出相似的简单git diff
对它们的改变。
E
:您所做的更改C
:它们发生了什么变化 Git从提交git diff --find-renames hash-of-E hash-of-G
中检出文件,即,您俩都是从 combines 开始的,对这些文件所做的更改,并使用 combined建立新的提交。 中的更改。这确定哪些文件/内容进入提交git diff --find-renames hash-of-E hash-of-C
:
E
新提交H
的第一个父级是 A--B--C <-- topic
/ \
D--E--F--G---H <-- master (HEAD)
,它是H
的尖端,也是您已签出的分支。它的第二个父级是G
,您告诉master
合并的那个。
请注意,当Git完成所有这些更改组合时,它对两个分支提示中的完全相同的所有文件都非常容易,因为无论情况如何,合并基础时,两个技巧匹配,因此两个文件都相同,并且两个都工作正常。如果您更改了文件X而没有更改文件X,以及您更改了文件Y而又没有更改文件X,那么这也很容易,因为再次声明,它可以只获取您或这些文件的版本。只有在您俩以不同的方式触摸了相同文件的地方,Git才需要努力工作。
当两组提交之间没有 通用连接时,就会发生不相关的历史记录:
C
您的提交从git merge
开始并向后进行,直到A--B--C <-- master (HEAD)
J--K--L <-- theirs
为止。 C
之前没有提交:A
没有父母。
在这种情况下,它们的提交从A
开始(我跳过了很多字母,以留出空间来插入我们的合并)。 A
的父母是L
,L
的父母是K
,但是K
也没有父母。因此根本没有共同的起点。
如果您告诉Git合并这些,Git只是假装有一个。假装的起点没有 no 个文件。 Git运行:
J
:您所做的更改J
:它们发生了什么变化当然,您从此差异中所做的更改是添加了每个文件(位于提交git diff empty-tree hash-of-C
中)。他们所做的更改是,他们添加了每个文件(位于其提交git diff empty-tree hash-of-L
中)。
如果文件具有不同的名称,则它们是不同的文件,并且没有问题:Git接受您或他们的文件。如果它们具有相同的名称,但内容完全相同,那么这里也没有冲突:Git可以接受您的(或他们的)名称。对于您和他们的文件具有相同名称但内容不同的所有文件,都会出现问题。就Git而言,您是从头开始的,他们也是,所以一切都冲突了。您必须从“一切冲突”输入中选择获奖内容或构建新文件。
一旦您解决了所有这些冲突并运行C
使Git完成,Git就会像往常一样进行合并提交:
L
新提交具有两个父git merge --continue
和A--B--C--D <-- master (HEAD)
/
J--K---L <-- theirs
,并永久保存通过修复Git报告的冲突而构建的快照,否则{中的任何文件都完全相同{1}}和C
或仅在 L
中或仅在C
中。
(“ Forever”有点太强大:保存的文件仅能持续到提交本身。但是,默认值是每次提交都可以永久存在。如果使提交消失,文件也会这样做。 )
答案 1 :(得分:0)
合并不相关的历史记录的过程是这样的:您想象每个历史记录的根源之前都有一个共同的祖先,根本没有内容。这是合并基础。