--allow-unrelated-histories flag

时间:2018-06-13 13:50:08

标签: git git-merge

情况如下:

  • 我克隆了一个正在进行的大型项目资源库RepoA
  • 将没有.git文件夹的所有文件复制到新文件夹RepoB
  • 在{RepoB
  • git init并添加了不同的远程
  • 我参与了RepoB并将许多提交推送到远程
  • 他们还推动了许多提交到RepoA

现在,我想将我的作品与他们的回购合并。这就是我在RepoA中所做的。

git checkout develop  
git remote add repoBOrigin https://www.cloud.com/repoB.git   
git fetch repoBOrigin aBranchOfRepoB // all of the work is in this branch  
git merge repoBOrigin/aBranchOfRepoB  

我收到了这个错误:fatal: refusing to merge unrelated histories

我在stackoverflow上查了一下,发现可以使用--allow-unrelated-histories标志来解决这个问题,但是会发出警告,这种情况应该在极少数情况下使用。

现在,我真正担心的是这个标志会产生什么影响/问题。 RepoA的git历史将如何形成?

没有人解释合并无关历史的后果。由于该项目的规模相当大,我必须非常小心才能将任何愚蠢的东西推到他们的回购中。

1 个答案:

答案 0 :(得分:1)

  

我真正担心的是--allow-unrelated-histories会产生什么影响/问题...

标志本身不会造成任何后果。它的作用是启用一个不是Git用户期望的行动。

要理解它 - 或者一般的Git,真的 - 你需要掌握一些关于图形的基本知识,正如通常的数学定义所定义的那样,图形 G 是顶点的集合 V 通过边 E 连接,或以通常的符号写入, G =(V,E)。当边缘有一个方向 - 一种单向箭头时,每个顶点(或节点)"进入"另一个顶点,但你不能回头,边缘被称为 arcs

在Git中,提交图的定向如下:每个提交充当图节点,并列出其父提交。这些是传出的弧,因此它们以一种倒退的方式连接提交。 Git的分支名称然后用于查找 last 提交,以便在一个很小的三个提交存储库中,您将拥有:

A  <-B  <-C   <--master

提交A是您做过的第一次提交,因此它没有父级。提交B列出提交A作为其父项,C列出B作为其父项;并且Git找到提交C - 其真实姓名,即其哈希ID,看起来非常随机 - 使用名称master来保存C的哈希ID。

知道这些链接 - 弧线 - 全部向后,从子到父,我们可以更方便地绘制链接,并添加更多提交:

A--B--C--D   <-- master
    \
     E--F--G   <-- branch

如果我们现在将合并分支重新转换回master,Git会使用这些连接箭头来确定您在master上的工作在哪里分开别人在branch工作。这回到了提交B,图表节点重新加入。因此,Git现在可以将此合并基础B中保存的快照与master的提示进行比较:

git diff --find-renames <hash-of-B> <hash-of-D>

找出的变化。然后Git可以将B中的快照与branch中的快照进行比较:

git diff --find-renames <hash-of-B> <hash-of-G>

合并的行为 - 合并动词 - 使这两个差异并组合起来,将组合的变化应用于基本提交中的任何内容。如果一切顺利,Git会自己提交最终结果。 (如果没有,Git会停止,并让你清理混乱并自己做提交;提交内容取决于如何修复Git发现的冲突。)结果是合并提交,而不是一个两个父母:

A--B--C--D---H   <-- master (HEAD)
    \       /
     E--F--G   <-- branch

同样,新合并提交H源代码快照组合自合并基础以来所做的更改的结果 - 公共起点两个分支提示。

但是,在您的情况下,您已经制作了两个无关的存储库。结果是数学家称之为disconnected graph。它可能看起来像这样,例如:

A--B--C--D---H   <-- br1
    \       /
     E--F--G

        L--M
       /    \
I--J--K------N   <-- br2

如果您现在git checkout这两个分支中的一个,以便HEAD附加到br1,然后运行git merge br2,Git就会找到共同点起点,从两个分支尖端向后(向左)工作。但是没有共同的起点:历史是无关的。

旧版本的Git将继续并合并。除非你提供旗帜,否则新人会抱怨;如果你提供旗帜,它们会以完全相同的方式继续合并。

这里的问题是没有共同的起点,所以Git所做的是假设公共起点是真正的空提交:提交没有文件就在里面。

这意味着新创建了两个分支中每个分支的每个文件。具有相同路径名的两个文件将导致&#34;添加/添加冲突&#34;:Git说从头开始编写README.txt,并且他们从头开始编写README.txt,而Git本身并不知道如何将这些结合起来,所以你必须自己做。对于每个具有相同名称的文件重复此操作。

另一方面,如果您创建了README.md并且他们创建了README.rst,则这两个名称会有所不同,因此Git假定将README.md与任何内容合并的正确方法是取README.md,将README.rst与任何内容合并的正确方法是README.rst。所以你最终得到了这两个文件,Git认为它们现在已正确组合。 (这是真的吗?我不知道.Git也没有,但Git 认为它是真的。)

这对所有文件都重复:要么每个文件名对于特定的差异都是唯一的,所以Git会添加它,或者它不是,所以Git声明冲突并由你来解决问题。最后,如果没有文件名冲突,Git会自行进行新的提交;如果有冲突,Git会让你清理它们并自己做。我们可以绘制新的提交:

A--B--C--D---H-----O   <-- br1 (HEAD)
    \       /     /
     E--F--G     /
                /
        L--M   /
       /    \ /
I--J--K------N   <-- br2

这是一件明智的事吗?我无法回答这个问题;只有你能回答。