git-subtree pull 合并冲突

24

所以我使用git-subtree将repoB的各个分支放在repoA的子目录中,如下所示

git clone repoA
cd repoA
// some commits to repoA here
git subtree add --prefix=src/dirA repoB branchA

我在repoA中做了几个提交,使用了

git subtree push --prefix=src/dirA repoB branchA

不久之后,我从另一个名为repoC的仓库向repoB/branchA提交了一些内容,其中branchA也是使用git-subtree添加的。

现在,我尝试

git subtree pull --prefix=src/dirA repoB branchA

然而,我出现了一个没有明显原因的合并冲突。更改很简单,根本不冲突——这已经通过补丁确认过了。
我不确定如何解决这个错误。我已经找到了另外四个与同样或类似问题相关的线程:
1. git-subtree pull complications 2. git subtree pull -P whatever <repo> <ref> always merge conflict 3. git-subtree conflict when pulling from central repo 4. Git Subtree Merging reports conflict when merging a simple upstream change(尽管这个是关于子树合并策略的,见下文)
我不确定这是否与不同的SHA-1有关,因为我没有rebase我的提交,也没有编辑它们; 链接1至3。
我的问题更像是链接4,其中git在执行简单合并时神奇地失败了。然而,链接3讨论了子树合并策略,而不是特定的git-subtree,所以我不确定这是否适用于我的情况。
虽然情况看起来相同:
<<<<<<< HEAD
=======
// changes from commit I try to pull from repoB/branchA
>>>>>>> {commit SHA-1 from commit I try to pull from repoB/branchA}

我注意到在三方合并窗口(kdiff3)中,BASE明显是错误的。然而,如果是这样,为什么git不尝试应用自base以来的所有早期提交?发出

git log --oneline

在合并失败之后但在合并/尝试合并之前,显示的提交中没有重复的提交。作为基础的文件版本是我最初发出时的文件版本。
git subtree add --prefix=src/dirA repoB branchA

在repoA内部。

那是怎么回事?似乎与git子树无法找到我的提交有关,但它没有尝试将BASE到HEAD~1的提交应用,而只是我实际缺少的提交HEAD。

如何修复此错误而不破坏任何存储库的历史记录?为什么git不能拉取这个简单的提交,而是认为它是合并冲突?

任何见解都将不胜感激。


我以前没有使用过子树,但是找到了这个关于合并它们的链接:http://git-scm.com/book/en/Git-Tools-Subtree-Merging。 - AgileDan
2个回答

42

好的,我解决了这个问题。这是一个双重问题。首先,我的树实际上看起来像这样:

Status Quo

我在我的树中有一个提交涉及到src/dirA,但当repoB/branchA已经继续推进时,该提交尚未被推送。

我发现,git subtree pull找不到正确的基础,因为它正在寻找共同祖先,因此它使用的是我最后一次合并树的版本,即我最初调用git subtree add时的版本。

现在,为了解决共同祖先的问题,必须执行git subtree split --rejoin,它执行了一个简单的合并,以便git再次找到正确的基础,即从repoA推送到repoB/branchA的提交之后。

但是,正如您可以在我的案例中看到的那样,git subtree split --rejoin后接一个git subtree pull不能解决我的问题:

Broken History after git subtree pull.

由于git subtree split创建了一个合成历史,其中包含所有与src/dirA有关的提交,无论它们是否已推送,SHA-1摘要会发生分歧。我将合成历史拆分为自己的分支split,以演示目的。

当然,在执行git subtree split --rejoin后,git subtree pull会成功。但是,下一个git subtree push将失败,因为此后repoB和合成树的历史完全不同。

因此,我必须返回到那个有问题的未推送提交之前,并从那里将更改拉入我的分支中。由于git subtree pull通过git merge仍然无法自行找到正确的基础,因此复杂化了这一过程。因此,仍需要使用git subtree split --rejoin
因此,我目前解决了我的问题是直接检出有问题的未推送src/dirA提交之前的提交。然后我执行了git subtree split --rejoin,然后是git subtree pull。当然,这会在我的主树中添加两个合并,我无法将其合并为一个合并,并且根据我在源代码中阅读到的内容,似乎没有简单的解决方案。
成功执行git subtree pull后,我将我的master分支上的剩余提交变基到master_fix上。现在,在repoA/master_fixrepoB/branchA的共享历史中,SHA-1摘要匹配。
当然,这种方法具有重新创建基础的常见缺点:如果其他人正在处理master,则他们的历史记录将被git branch -m master_fix master破坏。

5
我曾经遇到与“git subtree pull”相似的问题,会出现“fatal: refusing to merge unrelated histories”的错误。
对我有效的方法是直接使用“git merge”,具体来说是:
git merge -s subtree -Xsubtree="$prefix" subremote/branch --allow-unrelated-histories

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接