简体   繁体   English

从中央回购中拉出git-subtree冲突

[英]git-subtree conflict when pulling from central repo

I have several projects that depend on the same library, for which I'd like to maintain a separate git repository to be managed with git-subtree within each project. 我有几个依赖于同一个库的项目,为此我想维护一个单独的git存储库,以便在每个项目中使用git-subtree进行管理。 So for example, within each project I can do: 例如,在每个项目中,我可以做到:

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

Now in the course of working on project1, I make some changes to lib1, say lib1/file1.c, and push this back to the central repo: 现在在处理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

So far, so good. 到现在为止还挺好。 But now I'd like to update project2's copy of lib1. 但现在我想更新project2的lib1副本。 So I try: 所以我尝试:

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.

What's going on? 这是怎么回事? I know for certain that no changes were made to any of the lib1 files under project2, so why should there be a conflict here? 我确定没有对project2下的任何lib1文件进行任何更改,那么为什么会出现冲突呢?

The conflicts are half-empty, like those reported in this question . 冲突是半空的,就像这个问题中报道的那样。 Everything is being pulled/pushed within a single system (OS X), so I know there's no issue with line endings as suggested there. 所有东西都在一个系统(OS X)中被拉/推,所以我知道那里的线路结尾没有问题。

Surely this is a common use case for git-subtree, and has a simple answer I just can't see. 当然这是git-subtree的常见用例,并且有一个我看不到的简单答案。 Please help! 请帮忙!

EDIT: I found an unsatisfying workaround: immediately after pushing changes to the subtree, I need to re-run subtree pull: 编辑:我发现了一个令人不满意的解决方法:在将更改推送到子树后,我需要重新运行子树拉:

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

Even though there were no changes, it will find something, and do a merge commit. 即使没有变化,它也会找到一些东西,并进行合并提交。 Then, after making some changes elsewhere, the conflict won't happen the second time I pull from the central repo. 然后,在其他地方做了一些改变之后,第二次从中央仓库撤出时就不会发生冲突。 But if I forget to run pull immediately after pushing, the next pull will get this conflict. 但是如果我在推动后忘记立即拉动,那么下一次拉动就会发生这种冲突。

So now my question is, why does this work? 所以现在我的问题是,为什么这有效? Is there a bug in the way git-subtree tracks pushes, or am I missing something? git-subtree跟踪推送的方式是否有错误,或者我错过了什么?

I actually found the proper way to do this through some trial and error. 我实际上通过一些试验和错误找到了正确的方法。

After this command: 执行此命令后:

project1$  git subtree push --prefix=lib1 /path/to/lib1.git master

execute a fetch command: 执行获取命令:

project2$  git fetch /path/to/lib1.git master

and then do your pull: 然后做你的拉:

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

There is unfortunately no good way to split commits out of the tree without giving the newly-split commits totally different commit ids. 遗憾的是,没有很好的方法可以将提交从树中分离出来,而不会给新分裂提交完全不同的提交ID。 This is because they are, after all, different commits: they don't contain the parts that weren't in the subtree. 这是因为它们毕竟是不同的提交:它们不包含不在子树中的部分。 That means when you pull them back in, git will see them as entirely new commits and generate a conflict. 这意味着当你将它们拉回来时,git会将它们视为全新的提交并产生冲突。

There are two things you can do. 你可以做两件事。 One of the other answers suggested doing a git subtree pull right after you push. 其中一个答案建议你在推动后立即执行git子树拉。 This will work, but you end up with two copies of every commit because there really are technically two sets of changes: the upstream ones (auto-generated by git-subtree push/split) and the ones in your combined project, and you are merging them together. 这可以工作,但是你最终会得到每个提交的两个副本,因为技术上确实有两组更改:上游的(由git-subtree push / split自动生成)和组合项目中的那些,你是将它们合并在一起。 A shortcut for this method is the --rejoin option to split/push, which adds the extra merge commit right away. 此方法的快捷方式是split-push的--rejoin选项,它会立即添加额外的合并提交。

The second option is to use --squash . 第二种选择是使用--squash This also creates new merge commits, but since you merge all the changes from the upstream repository as a single commit instead of one per original commit, it causes less clutter in your history. 这也会创建新的合并提交,但由于您将来自上游存储库的所有更改合并为单个提交而不是每个原始提交一个,因此会导致历史记录中的混乱变得更少。 Most people seem to like it better with --squash . 大多数人似乎更喜欢--squash

Well, it seems to be a bug in git-subtree. 好吧,它似乎是git-subtree中的一个bug。 I evaluated it for my needs and gave up. 我根据自己的需求对其进行了评估并放弃了。 Basicaly, git-subtree push alters commit messages and thus, SHA1 of commit changes. Basicaly,git-subtree push改变提交消息,因此提交的SHA1更改。 You have to pull to merge additional commits which introduce exactly the same changes but just have different SHA1 hashes due to altered commit messages. 您必须提取合并其他提交,这些提交引入了完全相同的更改,但由于更改了提交消息,因此只有不同的SHA1哈希值。 GIT handles double merges (merging same changes again) correctly, so it silently notes the merge. GIT正确处理双重合并(再次合并相同的更改),因此它会静默地记录合并。

Someone has to fix it! 有人必须解决它!

Inside your main project, try to pull and push with squash commands always : 在您的主项目中,尝试始终使用squash命令进行拉动和推送:

step 1 : subtree pull with a squash 第1步:使用壁球拉下子树

 git subtree pull --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash

step 2 : subtree push with a squash 第2步:使用壁球推送子树

 git subtree push --prefix=mainProjectFolder/subtreeFolder http://bitbucket.org/repo.git master --squash

squash flag will avoid creation of new SHA1 id's for the same commit in different repositories. squash标志将避免为不同存储库中的相同提交创建新的SHA1 id。

Explanation : To over come this issue you can make it a convention to use the squash flag while pushing and pulling your subtree. 说明 :要解决这个问题,你可以在推送和拉动子树时使用壁球标志。 The issue described by @Borg about SHA1 commit id's is correct, but subtree were not really built for this. @Borg描述的关于SHA1提交id的问题是正确的,但是子树并没有真正为此构建。 You should avoid to keep the commit Id' of the subtree(library) repository in both the parent project and subtree project. 您应该避免在父项目和子项目中保留子树(库)存储库的提交Id'。 And if at all you push changes from the parent repository to the subtree repository follow this statement from the documentation(line 58): That is, if you make a change that affects both the library and the main application, commit it in two pieces. 如果你将更改从父存储库推送到子树存储库,请遵循文档中的此语句(第58行): 也就是说,如果进行影响库和主应用程序的更改,则将其提交为两部分。

Also this video explains it when not to use subtrees. 视频还解释了何时不使用子树。 Drag straight to 11:00 minutes to find that subtree's are not the correct solution for you if : 如果出现以下情况,请直接拖至11:00分钟,以发现该子树不是正确的解决方案:

you have constant updates to the repository, 你有不断更新的存储库,

or, if you have many dependencies, 或者,如果你有很多依赖,

or, if everyone in the team has to learn subtrees. 或者,如果团队中的每个人都必须学习子树。

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

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