git-subtree拉合并冲突 [英] git-subtree pull merge conflict
问题描述
git clone repoA
$ p $使用
cd repoA
//一些提交到repoA这里
git subtree add --prefix = src / dirA repoB branchA
git subtree push - 前缀= src / dirA repoB branchA
过了一段时间,我提交了一些repoB / branchA从另一个repoC ,其中branchA也是使用git-subtree添加的。
现在,我尝试
git subtree pull --prefix = src / dirA repoB branchA
然而,因没有明显的原因而导致合并冲突。这些变化很简单,根本不会发生冲突 - 就像patch所证实的那样。
我不确定如何解决这个错误。我已经找到了
两个四个处理相同/类似问题的其他线程:
我不确定这是否与不同的SHA-1有关,因为我没有重定义我的提交,也没有对它们进行编辑;链接1至3.
我的问题更像链接4,其中git奇迹般地无法进行简单的合并。然而,链接3谈到了子树合并策略,特别是git-subtree,所以我不确定这是否适用于我的情况。
情况虽然看起来是相同的:
<<<<<<<<<<<<<<<<<<<<<<<<<¥¥¥ HEAD
=======
//从commit提交我尝试从repoB / branchA中提取
>>>>>>> {从commit提交SHA-1我尝试从repoB / branchA中提取}
所以我注意到BASE在三向合并窗口(kdiff3)中显然是错误的。但是,如果是这样的话,为什么git不会尝试应用自基础之后的所有早期提交?发行
git log --oneline
在合并失败之后但在合并/尝试合并之前,在违规提交之前显示没有重复的提交。
显示为BASE的文件的版本是我第一次发布时的文件
git subtree add --prefix = src / dirA repoB branchA
在repoA中。
那是怎么回事?这似乎是相关的,由于某种原因,git子树无法找到我的提交,但它不会尝试将提交从BASE应用到HEAD〜1,而只是我实际上缺少的提交,HEAD。
我怎样才能解决这个错误,而无需破坏版本库的历史记录?为什么不能git拉这个简单的提交,而是认为这是一个合并冲突?
任何洞察力将不胜感激。
解决方案好的,所以我想通了。这是一个双管齐下的问题。首先,我的树看起来像这样:
我在我的树中提交了一个触及
src / dirA
的提交,但尚未推送repoB / branchA
已经移动了。
我发现
git subtree pull
不会找到正确的基础,因为它正在寻找一个共同的祖先,因此它在我最后一次合并树时使用了版本,即当我调用<$ c $现在,为了解决共同的祖先问题,需要git subtree split git subtree add
--rejoin ,它执行敷衍合并,所以git再次找到正确的基础,即在从repoA
推送到repoB / branchA
。
然而,正如你在我的例子中看到的那样,一个
git subtree split - 重新加入
然后是git子树拉
不能解决我的问题:
由于
git subtree split
会创建一个触及src / dirA
,无论它们是否被推动,SHA-1总和都是分歧的。出于演示目的,我将合成历史记录拆分为自己的分支split
。
git子树在
当然会成功。然而,下一个git subtree split --rejoin
之后,拉git子树push
将会失败,因为repoB
和合成树的历史在完成之后完全不同。
因此,我必须在违规的非推送提交之前回去,并将更改从那里拖到我的分支中。这很复杂,因为
git子树拉经由<$> git子树拆分--rejoin
仍然是必需的c $ c> git merge 仍然无法自行找出正确的基础。
所以我现在解决的方式我的问题是直接在违规的非推送
src / dirA
提交之前检出提交。然后我做了一个git subtree split --rejoin
,后面跟着一个git子树拉
。这当然会在我的主树中添加两个合并,我无法弄清楚如何压缩到一个合并中,并且从我在源代码中读到的内容看来,似乎并没有解决这个问题的简单方法。
在成功完成
git子树拉
之后,我将其余的提交从我的master
分支到master_fix
。现在SHA-1总共匹配repoA / master_fix
和repoB / branchA
共享历史记录。
这当然有一个通常的缺点:如果有人正在处理
master
,他们的历史将被git branch -m master_fix master
。So I used git-subtree to have various branches of repoB in sub-directories of repoA, like so
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
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.
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
twofour other threads that deal with the same/similar issue:
- git-subtree pull complications
- git subtree pull -P whatever <repo> <ref> always merge conflict
- git-subtree conflict when pulling from central repo
- Git Subtree Merging reports conflict when merging a simple upstream change (this one is about subtree merge strategy though, see below)
I'm not sure this is related to different SHA-1s as I did not rebase my commits nor did I edit them; links 1 thru 3.
My problem is more like link 4, where git magically fails to do a simple merge. 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.
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). However, if that's the case, why doesn't git try to apply all earlier commits since 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
git subtree add --prefix=src/dirA repoB branchA
inside 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.
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?
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 whenrepoB/branchA
had already moved on.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, i.e. when I calledgit subtree add
initially.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, i.e. after the commits pushed fromrepoA
torepoB/branchA
.However, as you can see in my case, a
git subtree split --rejoin
followed by agit subtree pull
does not solve my problems:Due to the fact that
git subtree split
creates a synthetic history of all commit that touchsrc/dirA
irrespective of the fact whether or not they were pushed, the SHA-1 sums diverge. I split the synthetic history into its own branchsplit
for demonstration purposes.
git subtree pull
will of course succeed aftergit subtree split --rejoin
. However, the nextgit subtree push
will fail, because the histories ofrepoB
and the synthetic tree are completely different after that.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, becausegit subtree pull
viagit merge
can still not figure out the correct base on its own.So the way I currently resolved my issue was by checking out the commit directly before the offending non-pushed
src/dirA
commit. Then I did agit subtree split --rejoin
followed by agit 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 mymaster
branch ontomaster_fix
. Now the SHA-1 sums match throughout the shared history ofrepoA/master_fix
andrepoB/branchA
.This of course has the usual drawbacks of a rebase: if somebody else was working on
master
, their history will be ruined bygit branch -m master_fix master
.这篇关于git-subtree拉合并冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!