Git 合并不会从另一个存储库中删除文件

Git merge does not deleting files from another repository

存在两个存储库:rep1、rep2。 两者都是来自同一 SVN 实例的单向同步的结果。 (SVN中的变化同步到git,但是git中的变化没有同步回SVN) 这两个存储库不是彼此的分支。

rep1/master 分支包含一个文件 file1.txt

rep2/master 分支包含文件 file1.txt,但文件已在 rep2/

中删除

rep2 作为远程添加到 rep1 中以便合并。 (远程 2)

分支 rep2/master 已创建

git checkout -b rep2_master_branch --track rep2/master

一个 "merge" 分支是从 rep1/master

的顶端创建的
git checkout -b merge-master-branches master 

使用选项 "theirs" 和压缩执行合并。 allow-unrelated-histories 是必需的,因为合并来自另一台服务器。

git merge -Xtheirs --squash rep2_master_branch  --allow-unrelated-histories

观察到 rep1/file1.txt 没有被删除。

进一步观察,合并期间的冲突已正确解决,修改和添加的文件也是如此。似乎唯一遗漏的是rep2中被删除的文件。

我该如何解决这个问题?或者更好的是,如何解决这个问题?

就Git而言,正确的合并结果。

Git 的 git merge 通过将两个分支提示与一个公共合并基础进行比较来工作。也就是说,如果你绘制提交图,它看起来像这样:

             o--o--L   <-- branch1
            /
...--o--o--*
            \
             o--o--R   <-- branch2

然后合并branch1(提交L)与branch2(提交R)的结果将通过比较提交[=20=的内容来计算],两个分支派生的共同点,到提交 L 的内容和提交 R.

的内容

*L 的任何变化都发生在左侧。从 *R 的任何变化都发生在右侧。 Git 组合这两个 "things that happened",将这些组合更改应用于 * 的内容,如果一切顺利,根据结果进行新的提交。

但是您正在使用 --allow-unrelated-histories。当 没有共同提交时 需要: 我们绘制 LR 的历史并发现他们从不偏离共同点。例如,我们可能会得到:

A--o--o--...--L   <-- branch1

B--o--...--o--R   <-- branch2

其中 AB 都是 根提交。那么应该Git使用什么作为共同的起点,来弄清楚从那以后发生了什么变化?

人们可以争论各种starting-points的选择,但Git的答案是:使用空提交。也就是说,--allow-unrelated-histories, Git 假装有一个根本没有文件的公共提交:

  A--o--o--...--L   <-- branch1
 /
*
 \
  B--o--...--o--R   <-- branch2

比较空的提交 * 和提交 L,Git 发现 branch1 上的每个文件都是按照它在L。比较 *R,Git 发现 branch2 上的每个文件都是按照它在 R 中的形式新建的。无论这些文件在哪里匹配,一切都很好:我们只需要那个文件。只要 L 有一个 R 没有的文件,反之亦然,一切都很好:我们只需要那个文件。只要 LR 都有一个文件,但它们的内容不同,我们就会发生合并冲突。

由于您使用了 -X theirs,Git 通过进行 "their" 更改来解决每个冲突("theirs" 是您指定的提交,而不是您作为HEAD) 自空 merge-base 提交以来。

如果你想让Git假装其他提交是合并基础,你可以使用git replace --graft插入一些假的父链接。例如,假设您想 fake-tie 将两者一起 arbitrarily-chosen 提交 C:

A--o--o--...--L   <-- branch1
         /
B--...--C--...--R   <-- branch2

以便 Git 将 CL 进行比较,并将 CR 进行比较。就 git merge 本身而言,您在 A--...--L 链中选择哪个提交并不重要; 任何 提交都可以(包括 AL 本身),但请注意 Git 只会 "see" 自提交以来发生变化选择(由于 C-vs-LC-vs-R 的差异)。因此,在链中选择一些合适的提交 运行:

git replace --graft <hash-ID-of-chosen-commit> <hash-ID-of-C>

和 Git 现在将使用替换(移植)提交而不是选择的提交。 git merge 现在将使用 C 的内容作为公共源。 (您可以在 git merge 退出后立即删除嫁接,即使它退出时出现合并冲突。因此您可以编写一个插入嫁接的小脚本,运行s git merge,并且删除嫁接,与 arbitrarily-chosen 祖先合并。只需将它作为 L 的替换插入,只要它在 B--...--R 行上,或者将它作为 [=19= 的替换插入] 只要它在 A--...--L 行。)