--allow-unrelated-histories 标志的后果

Mur*_*ati 2 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  
Run Code Online (Sandbox Code Playgroud)

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

我在 stackoverflow 上查找了这个问题,发现可以通过使用--allow-unrelated-historiesflag 来解决这个问题,但这会附带一个警告,表明应该在极少数情况下使用它。

现在,我真正关心的是这个标志会导致什么后果/问题。RepoA 的 git 历史将如何形成?

没有人解释合并不相关历史的后果。由于该项目规模相当大,因此在将任何愚蠢的内容推送到他们的仓库之前我必须非常小心。

tor*_*rek 6

\n

我真正关心的是影响/问题--allow-unrelated-histories会导致什么影响/问题......

\n
\n\n

旗帜本身不会造成任何影响。它的作用是启用新 Git 用户所不期望的操作。

\n\n

要理解\xe2\x80\x94或一般的Git,实际上\xe2\x80\x94你需要有一些关于图的基本知识,正如通常的数学定义所定义的那样,其中图G是由边连接的顶点V的集合E,或用通常的符号写成G = (V, E)。当边有一个方向\xe2\x80\x94a 一种单向箭头,使得每个顶点(或节点)“前往”另一个顶点但不一定能返回时,这些边称为

\n\n

在 Git 中,提交图是这样定向的:每个提交充当图节点,并列出其父提交。这些是传出弧,因此它们以某种向后的方式连接提交。然后Git 的分支名称会找到最后一个提交,因此在一个小型的三提交存储库中,您将拥有:

\n\n
A  <-B  <-C   <--master\n
Run Code Online (Sandbox Code Playgroud)\n\n

提交A是您所做的第一个提交,因此它没有父级。CommitB将 commitA列为其父级,并C列出B为其父级;Git 找到提交C\xe2\x80\x94,其真实名称(即其哈希 ID)看起来相当随机\xe2\x80\x94,使用名称master来保存C\ 的哈希 ID。

\n\n

知道这些链接\xe2\x80\x94和弧\xe2\x80\x94都向后,从子到父,我们可以更方便地将它们绘制为链接,并添加更多提交:

\n\n
A--B--C--D   <-- master\n    \\\n     E--F--G   <-- branch\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果我们现在将分支合并master,Git 使用这些连接箭头来找出历史上您的工作master与其他人的工作在哪里分开branch。回到 commit 处B,图节点重新加入。B所以 Git 现在可以将这个合并库中保存的快照与master提示进行比较:

\n\n
git diff --find-renames <hash-of-B> <hash-of-D>\n
Run Code Online (Sandbox Code Playgroud)\n\n

找出改变了什么。B然后 Git 可以将快照与提示中的快照进行比较branch

\n\n
git diff --find-renames <hash-of-B> <hash-of-G>\n
Run Code Online (Sandbox Code Playgroud)\n\n

合并\xe2\x80\x94以合并动词\xe2\x80\x94的行为使这两个差异并组合它们,将组合的更改应用到基本提交中的任何内容。如果一切顺利,Git 会自行提交最终结果。(如果没有,Git 会停止,让你清理混乱并自己进行提交;提交的内容取决于如何修复 Git 发现的冲突。)结果是合并提交,不是一个而是两个父项:

\n\n
A--B--C--D---H   <-- master (HEAD)\n    \\       /\n     E--F--G   <-- branch\n
Run Code Online (Sandbox Code Playgroud)\n\n

同样,新合并提交的源代码快照是合并自合并基\xe2\x80\x94(两个分支提示的共同起点)以来所做更改H的结果。

\n\n

然而,就您而言,您创建了两个不相关的存储库。结果就是数学家所说的断开图。它可能看起来像这样,例如:

\n\n
A--B--C--D---H   <-- br1\n    \\       /\n     E--F--G\n\n        L--M\n       /    \\\nI--J--K------N   <-- br2\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果您现在git checkout这两个分支之一,例如HEAD附加到 ,br1并运行git merge br2,Git 就会找到共同的起点,从两个分支提示向后(向左)工作。但没有共同的起点:历史互不相关。

\n\n

旧版本的 Git 只会继续进行合并。除非你提供标志,否则新人会抱怨;如果您提供标志,它们就会以完全相同的方式继续并合并。

\n\n

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

\n\n

这意味着两个分支中的每个文件都是新创建的。两个具有相同路径名的文件会导致“添加/添加冲突”:Git 说你是README.txt从头开始写的,而他们也是从头开始写的README.txt,而 Git 本身不知道如何组合这些,所以你必须自己动手。对每个具有相同名称的文件重复此操作。

\n\n

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

\n\n

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

\n\n
A--B--C--D---H-----O   <-- br1 (HEAD)\n    \\       /     /\n     E--F--G     /\n                /\n        L--M   /\n       /    \\ /\nI--J--K------N   <-- br2\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是明智之举吗?我无法回答这个问题;只有你能回答这个问题。

\n