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
。当 没有共同提交时 仅 需要: 我们绘制 L
和 R
的历史并发现他们从不偏离共同点。例如,我们可能会得到:
A--o--o--...--L <-- branch1
B--o--...--o--R <-- branch2
其中 A
和 B
都是 根提交。那么应该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
没有的文件,反之亦然,一切都很好:我们只需要那个文件。只要 L
和 R
都有一个文件,但它们的内容不同,我们就会发生合并冲突。
由于您使用了 -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 将 C
与 L
进行比较,并将 C
与 R
进行比较。就 git merge
本身而言,您在 A--...--L
链中选择哪个提交并不重要; 任何 提交都可以(包括 A
和 L
本身),但请注意 Git 只会 "see" 自提交以来发生变化选择(由于 C
-vs-L
和 C
-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
行。)
存在两个存储库: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
。当 没有共同提交时 仅 需要: 我们绘制 L
和 R
的历史并发现他们从不偏离共同点。例如,我们可能会得到:
A--o--o--...--L <-- branch1
B--o--...--o--R <-- branch2
其中 A
和 B
都是 根提交。那么应该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
没有的文件,反之亦然,一切都很好:我们只需要那个文件。只要 L
和 R
都有一个文件,但它们的内容不同,我们就会发生合并冲突。
由于您使用了 -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 将 C
与 L
进行比较,并将 C
与 R
进行比较。就 git merge
本身而言,您在 A--...--L
链中选择哪个提交并不重要; 任何 提交都可以(包括 A
和 L
本身),但请注意 Git 只会 "see" 自提交以来发生变化选择(由于 C
-vs-L
和 C
-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
行。)