git-subtree拉合并冲突

时间:2014-08-13 19:08:15

标签: git git-subtree

所以我使用git-subtree在repoA的子目录中有各种repoB分支,就像这样

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(这个是关于子树合并策略,但见下文)
  5. 我不确定这与不同的SHA-1有关,因为我没有重新提交我的提交,也没有编辑它们;链接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}
    

    所以我注意到BASE在三向合并窗口(kdiff3)中显然是错误的。但是,如果是这种情况,为什么git尝试不应用所有早期的提交?发布

    git log --oneline
    

    在合并失败之后但在合并/尝试合并之前显示在违规提交之前没有重复的提交。 显示为BASE的文件版本是我第一次发布时的文件

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

    内部repoA。

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

    如何在不搞砸任何存储库历史的情况下修复此错误?为什么不能git拉这个简单的提交,而是认为这是合并冲突?

    非常感谢任何见解。

2 个答案:

答案 0 :(得分:27)

好的,所以我想出来了。这是一个双管齐下的问题。首先,我的树实际上看起来像这样:

Status Quo

我的树中有一个提交src/dirA,但在repoB/branchA已经移动时尚未推送。

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

现在,为了解决共同的祖先问题,必须执行git subtree split --rejoin,它执行敷衍的合并,因此git再次找到正确的基础,即在将提交从repoA推送到{{1 }}

但是,正如您在我的案例中所看到的,repoB/branchA后跟git subtree split --rejoin并不能解决我的问题:

Broken History after git subtree pull.

由于git subtree pull创建了触及git subtree split的所有提交的综合历史记录,而不管它们是否被推送,因此SHA-1总和发散。为了演示目的,我将合成历史分成了自己的分支src/dirA

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

因此,我必须在违规的非推送提交之前返回并将更改从那里拉入我的分支。由于repoB通过git subtree split --rejoin仍然无法找到正确的基础,因此这很复杂。

Final solution to my problem

所以我目前解决我的问题的方法是在违规的非推送git subtree pull提交之前直接签出提交。然后我做了git merge后跟src/dirA。这当然会在我的主树中添加两个合并,我无法弄清楚如何压缩到一个合并中,而且从我在源代码中看到的内容来看,似乎并不是解决该问题的简单方法。 / p>

成功git subtree split --rejoin后,我将剩余的提交从git subtree pull分支重新定位到git subtree pull。现在,SHA-1总和在mastermaster_fix的共享历史记录中匹配。

这当然有一个反叛的常见缺点:如果其他人正在处理repoA/master_fix,他们的历史将被repoB/branchA毁掉。

答案 1 :(得分:1)

我遇到了类似的问题,因为 git subtree pull 会因 fatal: refusing to merge unrelated histories 而失败。

对我有用的是直接使用 git merge,更具体地说:

git merge -s subtree -Xsubtree="$prefix" subremote/branch --allow-unrelated-histories