简体   繁体   English

将Git子模块转换为子树后合并错误

[英]Merge error after converting Git submodule to subtree

I have a project where I was originally using submodules for some dependent code. 我有一个项目,我最初使用子模块的一些相关代码。 It turns out that submodules are not really appropriate for this project (and they are hard to use in practice), so I am converting each submodule to a subtree (using the new git-subtree feature). 事实证明,子模块并不适合这个项目(并且它们在实践中很难使用),因此我将每个子模块转换为子树(使用新的git-subtree特征)。

In my working repository, I have successfully removed each submodule and have added the old submodule repo as a subtree. 在我的工作存储库中,我已经成功删除了每个子模块,并将旧的子模块repo添加为子树。 No problem with this. 没问题。

When I go to another clone and attempt to pull from the first one, I get the following error from the merge step: 当我转到另一个克隆并尝试从第一个克隆拉出时,我从合并步骤中收到以下错误:

error: The following untracked working tree files would be overwritten by merge:
        sub/.gitignore
        sub/Makefile
        sub/README
        sub/src/main.c
        ... and so on for all files in sub/
Aborting

It seems that this is because the files in sub/ never really existed in the main repository in the first place, and when Git applies the patch to update .gitmodules it doesn't remove the directory with the submodule files. 这似乎是因为sub/的文件首先从未真正存在于主存储库中,并且当Git应用补丁来更新.gitmodules它不会删除带有子模块文件的目录。 When processing the next commit, where Git tries to create the new files in sub/ that are now part of the main repository, all those files conflict with the still-existing files in sub/ . 当处理下一个承诺,在Git的尝试创建新的文件sub/现在的主要仓库的部分,全部用在仍然存在的文件这些文件冲突sub/

The workaround I have found is to use rm -rf sub before git pull , which avoids this problem. 我发现的解决方法是在git pull之前使用rm -rf sub ,这可以避免这个问题。

My question is, is there any command line switch I can use with git merge that says "Overwrite any files that happen to exist in the working directory"? 我的问题是,是否有任何命令行开关,我可以使用git merge ,说“覆盖工作目录中恰好存在的任何文件”? Even better would be a feature where git merge would look at the contents of the existing file, and if the contents are identical to the file it was going to create anyway, suppress the error message and continue. 更好的是git merge将查看现有文件内容的功能,如果内容与它将要创建的文件相同,则禁止显示错误消息并继续。

UPDATE : I have created Git repositories that demonstrate this problem, to show exactly what I'm talking about. 更新 :我已经创建了演示此问题的Git存储库,以准确显示我正在谈论的内容。 To reproduce: 重现:

$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git merge origin/branch

This should result in the error message 这应该导致错误消息

error: The following untracked working tree files would be overwritten by merge:
    sub/Makefile
    sub/README
    sub/src/main.c
Please move or remove them before you can merge.
Aborting

I know your question was specific to merge, but I've had similar problems with merging git submodules. 我知道你的问题是特定的合并,但我在合并git子模块时遇到了类似的问题。 I think this solution will work with your problem, even if it's not directly addressing the merge question. 我认为这个解决方案可以解决您的问题,即使它没有直接解决合并问题。

I've found that by forcibly checking out the branch you want to merge, then going back to master, everything works out with submodules. 我发现通过强行检查你想要合并的分支,然后回到master,一切都与子模块一致。

To get things working in your example: 为了让你的例子工作:

$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git checkout -f origin/branch
$ git checkout master
$ git merge origin/branch

This works because it's basically doing your rm -rf step for you. 这是有效的,因为它基本上是为你做rm -rf步骤。 Granted, this is a bit roundabout, and maybe not worth doing if you only have the one submodule like your example does. 当然,这有点迂回,如果你只有像你的例子那样只有一个子模块,也许不值得做。 But I've found it to be quite the timesaver when working in a project with many submodules. 但是我发现在一个包含许多子模块的项目中工作非常节省时间。

Also, as has been pointed out in the comments, if you want to avoid making changes to the work tree, you can use this: 另外,正如评论中指出的那样,如果您想避免对工作树进行更改,可以使用以下命令:

$ git clone https://github.com/ghewgill/q14224966.git
$ cd q14224966
$ git submodule init
$ git submodule update
$ git reset origin/branch
$ git reset --hard master

This works in roughly the same way, but avoids checking out other files in the process. 这大致以相同的方式工作,但避免在过程中检出其他文件。 I haven't had a chance to use this in the wild, but it seems like a sound method. 我没有机会在野外使用它,但它似乎是一种合理的方法。

There's also $ git merge -s subtree origin/branch . 还有$ git merge -s subtree origin/branch It works with your example, but I've had unexpected results with it when more than one submodule is involved. 它适用于您的示例,但是当涉及多个子模块时,我有意外的结果。 You might have better luck, though. 不过,你可能会有更好的运气。

You can't get git-merge (or any other command) to forcibly clobber files it doesn't think it knows about, no. 你不能得到git-merge (或任何其他命令)强制破坏它认为不知道的文件,不。 git tries pretty hard not to do anything totally irreversible. git很难不做任何完全不可逆转的事情。

But with many submodules, you can make your deletion a bit easier and safer with git submodule foreach : 但是对于许多子模块,使用git submodule foreach 可以使删除更简单,更安全:

$ git submodule foreach 'rm -rf $toplevel/$path'
Entering 'sub'
$ git merge origin/branch
Updating a231acd..6b4d2f4
Fast-forward
...

(Caveat: I've never worked with subtrees and I don't know how complicated your actual repo is, so these solutions may not actually work for you.) (警告:我从未使用过子树,我不知道你的实际回购有多复杂,所以这些解决方案可能实际上并不适合你。)

From playing around with your sample repo, I've found two solutions that both seems to work, though they produce different commit trees: 从玩你的样本回购开始,我发现两个似乎都有效的解决方案,尽管它们产生了不同的提交树:

  1. Use git merge -s resolve origin/branch 使用git merge -s resolve origin/branch

     ~/q14224966[master]> git reset --hard origin/master HEAD is now at a231acd add submodule ~/q14224966[master]> touch other.c && git add . && git commit -m "New commit." [master bc771ac] New commit. 0 files changed create mode 100644 other.c ~/q14224966[master]> git merge -s resolve origin/branch Trying really trivial in-index merge... error: Merge requires file-level merging Nope. Trying simple merge. Simple merge failed, trying Automatic merge. Adding sub/Makefile Adding sub/README Adding sub/src/main.c Merge made by the 'resolve' strategy. .gitmodules | 3 --- sub | 1 - sub/Makefile | 1 + sub/README | 1 + sub/src/main.c | 1 + 5 files changed, 3 insertions(+), 4 deletions(-) delete mode 160000 sub create mode 100644 sub/Makefile create mode 100644 sub/README create mode 100644 sub/src/main.c ~/q14224966[master]> ls README main.c other.c sub/ ~/q14224966[master]> cd sub/ ~/q14224966/sub[master]> ls Makefile README src/ ~/q14224966/sub[master]> git status # On branch master # Your branch is ahead of 'origin/master' by 5 commits. # nothing to commit (working directory clean) ~/q14224966/sub[master]> cd .. ~/q14224966[master]> git status # On branch master # Your branch is ahead of 'origin/master' by 5 commits. # nothing to commit (working directory clean) 

    Here's the resulting commit tree: 这是生成的提交树: git commit tree  - 合并选项

  2. Use a rebase instead of a merge: 使用rebase而不是合并:

     ~/q14224966[master]> git reset --hard origin/master HEAD is now at a231acd add submodule ~/q14224966[master]> touch other.c && git add . && git commit -m "New commit." [master ae66060] New commit. 0 files changed create mode 100644 other.c ~/q14224966[master]> git rebase origin/branch First, rewinding head to replay your work on top of it... Applying: New commit. ~/q14224966[master]> ls README main.c other.c sub/ ~/q14224966[master]> cd sub/ ~/q14224966/sub[master]> ls Makefile README src/ ~/q14224966/sub[master]> git status # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # nothing to commit (working directory clean) ~/q14224966/sub[master]> cd .. ~/q14224966[master]> git status # On branch master # Your branch is ahead of 'origin/master' by 4 commits. # nothing to commit (working directory clean) 

    Here's the resulting commit tree: 这是生成的提交树: git commit tree  -  rebase选项

It tried 它试过了

git fetch --all git fetch --all

git reset --hard origin/master git reset - hard origin / master

but it doesn't work. 但它不起作用。

You can use the 'ours' merge strategy: 您可以使用“我们的”合并策略:

git merge -s ours old-master git merge -s我们的老主人

You can also use git-stash to save your changes then git-stash apply to restore them. 您还可以使用git-stash保存更改,然后使用git-stash来恢复它们。

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

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