简体   繁体   English

git-subtree 拉合并冲突

[英]git-subtree pull merge conflict

So I used git-subtree to have various branches of repoB in sub-directories of repoA, like so所以我使用 git-subtree 在 repoA 的子目录中有 repoB 的各种分支,就像这样

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

I did a few commits in repoA using我在 repoA 中使用了一些提交

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

Some time later, I committed something to repoB/branchA from another repoC, where branchA was added using git-subtree, too.一段时间后,我从另一个 repoC 向 repoB/branchA 提交了一些内容,其中也使用 git-subtree 添加了 branchA。

Now, I try现在,我尝试

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

However, I'm getting a merge conflict for no apparent reason.但是,我无缘无故地遇到了合并冲突。 The changes are simple and don't conflict at all -- as confirmed by patch.更改很简单,根本不冲突——正如补丁所确认的那样。

I'm unsure how to fix this error.我不确定如何解决这个错误。 I already found two four other threads that deal with the same/similar issue:我已经找到了另外四个处理相同/类似问题的线程:

  1. git-subtree pull complications git-subtree pull 并发症
  2. git subtree pull -P whatever <repo> <ref> always merge conflict git subtree pull -P what <repo> <ref> 总是合并冲突
  3. git-subtree conflict when pulling from central repo 从中央仓库中提取时出现 git-subtree 冲突
  4. Git Subtree Merging reports conflict when merging a simple upstream change (this one is about subtree merge strategy though, see below) Git 子树合并在合并一个简单的上游更改时报告冲突(尽管这是关于子树合并策略,请参见下文)

I'm not sure this is related to different SHA-1s as I did not rebase my commits nor did I edit them;我不确定这是否与不同的 SHA-1 相关,因为我没有重新设置提交,也没有编辑它们; links 1 thru 3.链接 1 到 3。

My problem is more like link 4, where git magically fails to do a simple merge.我的问题更像是链接 4,其中 git 神奇地无法进行简单的合并。 However, link 3 talks about the subtree merge strategy, not git-subtree in particular, so I'm not sure if this is applicable at all in my situation.但是,链接 3 讨论了子树合并策略,而不是特别是 git-subtree,所以我不确定这是否适用于我的情况。

Situation looks to be the same though:情况看起来是一样的:

<<<<<<< HEAD
=======
// changes from commit I try to pull from repoB/branchA
>>>>>>> {commit SHA-1 from commit I try to pull from repoB/branchA}

So I noticed that BASE is blatantly wrong in a three-way merge window (kdiff3).所以我注意到 BASE 在三路合并窗口 (kdiff3) 中明显错误。 However, if that's the case, why doesn't git try to apply all earlier commits since base?但是,如果是这种情况,为什么 git 不尝试应用自 base 以来的所有早期提交? Issuing发行

git log --oneline

after the failed merge but before merging/trying to merge shows no duplicated commits prior to the offending commit.在合并失败之后但在合并/尝试合并之前显示在违规提交之前没有重复提交。 The version of the file that's shown as BASE is the file as it was when I first issued显示为 BASE 的文件版本是我第一次发布时的文件

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

inside repoA.在 repoA 中。

So what's going on?发生什么了? It seems to be related that git subtree cannot find my commits for some reason, yet it does not try to apply the commit from BASE to HEAD~1, but only the commit I'm actually missing, HEAD.似乎与 git subtree 由于某种原因找不到我的提交有关,但它没有尝试将提交从 BASE 应用到 HEAD~1,而只是我实际上缺少的提交,HEAD。

How can I fix this error without screwing up either repository's history?如何在不破坏任一存储库历史记录的情况下修复此错误? Why can't git pull this simple commit and instead thinks it's a merge conflict?为什么git不能拉这个简单的提交,而是认为这是一个合并冲突?

Any insight will be much appreciated.任何见解将不胜感激。

Ok, so I figured this out.好的,所以我想通了。 It was a two-pronged problem.这是一个两方面的问题。 First of all, my tree actually looked like this:首先,我的树实际上是这样的:

现状

I had a commit in my tree that touched src/dirA , but was not yet pushed when repoB/branchA had already moved on.我在我的树中有一个触及src/dirA ,但是当repoB/branchA已经移动repoB/branchA没有被推送。

I discovered that git subtree pull would not find the right base, because it is looking for a common ancestor, hence it used the version when I had last merged the trees, ie when I called git subtree add initially.我发现git subtree pull找不到正确的基础,因为它正在寻找一个共同的祖先,因此它使用了我上次合并树时的版本,即当我最初调用git subtree add

Now, to resolve the common ancestor problem, one has to git subtree split --rejoin , which performs a perfunctory merge, so git finds the right base again, ie after the commits pushed from repoA to repoB/branchA .现在,要解决共同祖先问题,必须git subtree split --rejoin ,它执行敷衍合并,因此 git 再次找到正确的基础,即在提交从repoA推送到repoB/branchA

However, as you can see in my case, a git subtree split --rejoin followed by a git subtree pull does not solve my problems:但是,正如您在我的情况下所看到的, git subtree split --rejoin后跟git subtree pull并不能解决我的问题:

git subtree pull 后的破碎历史。

Due to the fact that git subtree split creates a synthetic history of all commit that touch src/dirA irrespective of the fact whether or not they were pushed, the SHA-1 sums diverge.由于git subtree split会创建所有接触src/dirA提交的综合历史记录,而不管它们是否被推送,SHA-1 总和存在分歧。 I split the synthetic history into its own branch split for demonstration purposes.出于演示目的,我将合成历史split为自己的分支split

git subtree pull will of course succeed after git subtree split --rejoin . git subtree pull当然会在git subtree split --rejoin之后成功。 However, the next git subtree push will fail, because the histories of repoB and the synthetic tree are completely different after that.但是,接下来的git subtree push会失败,因为之后repoB和合成树的历史完全不同。

Therefore, I had to go back before the offending non-pushed commit and pull the changes into my branch from there.因此,我不得不在有问题的非推送提交之前返回并将更改从那里拉入我的分支。 This is complicated by the fact that git subtree split --rejoin is still necessary, because git subtree pull via git merge can still not figure out the correct base on its own.由于git subtree split --rejoin仍然是必要的,这使情况变得复杂,因为git subtree pull通过git merge仍然无法自己找出正确的基础。

我的问题的最终解决方案

So the way I currently resolved my issue was by checking out the commit directly before the offending non-pushed src/dirA commit.所以我目前解决我的问题的方法是在有问题的非推送src/dirA提交之前直接检查提交。 Then I did a git subtree split --rejoin followed by a git subtree pull .然后我做了一个git subtree split --rejoin然后是一个git subtree pull This of course adds two merges into my main tree, which I could not figure out how to squash into one merge, and from what I read in source code, there doesn't seem to be an easy solution to that problem.这当然会在我的主树中添加两个合并,我无法弄清楚如何将其压缩为一个合并,并且从我在源代码中读取的内容来看,似乎没有一个简单的解决方案来解决这个问题。

After the successful git subtree pull , I rebased the remaining commits from my master branch onto master_fix .在成功git subtree pull ,我将master分支中剩余的提交重新定位到master_fix Now the SHA-1 sums match throughout the shared history of repoA/master_fix and repoB/branchA .现在 SHA-1 总和在repoA/master_fixrepoB/branchA整个共享历史中匹配。

This of course has the usual drawbacks of a rebase: if somebody else was working on master , their history will be ruined by git branch -m master_fix master .这当然有 rebase 的常见缺点:如果其他人在master工作,他们的历史将被git branch -m master_fix master破坏。

I had a similar problem as git subtree pull would fail with fatal: refusing to merge unrelated histories .我有一个类似的问题,因为git subtree pull会失败并fatal: refusing to merge unrelated histories

What worked for me was using git merge directly, more specifically:对我git merge直接使用git merge ,更具体地说:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM