从中央回购中提取时git子树冲突

从中央回购中提取时git子树冲突,git,git-subtree,Git,Git Subtree,我有几个项目依赖于同一个库,为此我想维护一个单独的git存储库,在每个项目中使用git子树进行管理。例如,在每个项目中,我可以做: project1$ git subtree add --prefix=lib1 /path/to/lib1.git master project2$ git subtree add --prefix=lib1 /path/to/lib1.git master 现在在处理project1的过程中,我对lib1做了一些更改,比如lib1/file1.c,并将其推回

我有几个项目依赖于同一个库,为此我想维护一个单独的git存储库,在每个项目中使用git子树进行管理。例如,在每个项目中,我可以做:

project1$  git subtree add --prefix=lib1 /path/to/lib1.git master
project2$  git subtree add --prefix=lib1 /path/to/lib1.git master
现在在处理project1的过程中,我对lib1做了一些更改,比如lib1/file1.c,并将其推回到中央回购协议:

project1$  git add lib1/file1.c
project1$  git commit -m "updates to lib1"
project1$  git subtree push --prefix=lib1 /path/to/lib1.git master
到目前为止,一切顺利。但现在我想更新project2的lib1副本。所以我试着:

project2$  git subtree pull --prefix=lib1 /path/to/lib1.git master
Auto-merging lib1/file1.c
CONFLICT (content): Merge conflict in lib1/file1.c
Automatic merge failed; fix conflicts and then commit the result.
发生什么事了?我可以肯定地知道,project2下的任何lib1文件都没有更改,所以这里为什么会有冲突呢

这些冲突是半空的,就像在中报告的那样。所有东西都是在一个系统(OSX)中拉/推的,所以我知道这里建议的行结束没有问题

当然,这是git子树的一个常见用例,有一个简单的答案我就是看不出来。请帮忙

编辑:我发现了一个不令人满意的解决方法:将更改推送到子树后,我需要立即重新运行子树拉取:

project1$  git subtree push --prefix=lib1 /path/to/lib1.git master
project1$  git subtree pull --prefix=lib1 /path/to/lib1.git master
即使没有更改,它也会找到一些内容,并执行合并提交。那么,在其他地方做了一些改变之后,我第二次退出中央回购协议时,冲突就不会发生了。但是,如果我在推后忘记立即运行pull,下一次拉动将导致此冲突


所以现在我的问题是,为什么这样做?git子树跟踪推送的方式中是否存在缺陷,或者我是否遗漏了什么?

嗯,这似乎是git子树中的一个缺陷。我根据自己的需要对它进行了评估 放弃了。基本上,git子树推送会改变提交消息,从而改变提交更改的SHA1。您必须拉合并其他提交,这些提交引入了完全相同的更改,但由于更改了提交消息而具有不同的SHA1哈希。GIT正确地处理双重合并(再次合并相同的更改),因此它会默默地记录合并


总得有人来修理它

通过一些尝试和错误,我实际上找到了正确的方法

在此命令之后:

project1$  git subtree push --prefix=lib1 /path/to/lib1.git master
执行fetch命令:

project2$  git fetch /path/to/lib1.git master
然后拉一下:

project2$  git subtree pull --prefix=lib1 /path/to/lib1.git master

不幸的是,如果不给新拆分的提交提供完全不同的提交ID,就无法将提交从树中拆分出来。这是因为它们毕竟是不同的提交:它们不包含不在子树中的部分。这意味着,当您将它们拉回来时,git会将它们视为全新的提交并生成冲突

你可以做两件事。另一个答案建议在你按下后立即进行git子树拉动。这会起作用,但每次提交都会有两个副本,因为从技术上讲,确实有两组更改:上游更改(由git子树推/拆分自动生成)和组合项目中的更改,并且您要将它们合并在一起。此方法的一个快捷方式是split/push的
--rejoin
选项,它会立即添加额外的合并提交


第二个选项是使用
--squash
。这也会创建新的合并提交,但由于您将上游存储库中的所有更改合并为单个提交,而不是每个原始提交一个,因此历史记录中的混乱会减少。大多数人似乎更喜欢使用
--squash

在主项目中,尝试使用squash命令拉和推:

步骤1:使用挤压工具拉动子树

 git subtree pull --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash
 git subtree push --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash
步骤2:使用挤压推送子树

 git subtree pull --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash
 git subtree push --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash
挤压标志将避免为不同存储库中的相同提交创建新的SHA1 id

说明: 为了解决这个问题,您可以在推拉子树时使用挤压标志。@Borg描述的关于SHA1提交id的问题是正确的,但子树并不是为此而构建的。您应该避免在父项目和子树项目中同时保留子树(库)存储库的提交Id。如果您将更改从父存储库推送到子树存储库,请遵循文档中的以下语句(第58行):

这也解释了何时不使用子树。如果出现以下情况,请直接拖动到11:00分钟,发现子树不是正确的解决方案:

您不断更新存储库

或者,如果您有许多依赖项

或者,如果团队中的每个人都必须学习子树


尽管如此,我还是要看一看受影响的线路。CR可能以某种方式潜入,例如,通过粘贴来自其他来源的文本。我在每个步骤都检查了文件的hexdump,没有CR(0d),只有LF(0a)。所以这不是问题,尽管检查起来很好。当然,这可能是某种bug。毕竟,Git子树是相对较新的。如果你能想出一个可复制的测试用例,你可以写信给git邮件列表。有没有人找到更好的解决方法,或者git的更新版本解决了这个问题?这就解释了为什么push-then-pull可以像它那样工作,谢谢。令人沮丧的是,子树无法自动处理如此简单的场景。是否有一种不同的方法来进行推送,以避免更改SHA1,或者我们回到使用子模块?看起来它还没有修复。我现在也有同样的问题。这必须是公认的答案。正是我需要的。