git:我可以子树合并存储库的子路径吗?
我有遥控器 Foo 和 Bar。 Foo 是一个具有大量目录的 Web 应用程序,其中相关的是 /public
,其中包含各种文件和其他目录。
Bar 是一组库和前端不使用的东西,因此,它应该放在 Foo 中的 /public/bar
中。 Foo 那里没有文件。
通过子模块或子树合并,这一切都是小菜一碟。 然而……
Bar 的树很混乱,它有各种预生产文件,如 PSD 和 FLA,其中唯一真正有用的部分是其 /www/tools
内的内容。
所以,我想做的是将 Bar 的 /www/tools
合并到 Foo 的 /public/bar
中,并假装 Bar 树的其余部分根本不存在。
可以做?
(我认为这与您从最初将您的项目合并为子树的项目中合并的方式非常相似。我也不知道该怎么做。)
I have the remotes Foo and Bar. Foo is a web application that has lots of directories, relevant amongst them is /public
which contains assorted files and other directories.
Bar is a set of libraries and whatnot used on the front end, as such, it should go in /public/bar
in Foo. Foo has no files there.
That would all be piece of cake with either submodules or subtree merge. However…
Bar's tree is messy, it has all sorts of pre-production files like PSDs and FLAs, and the only really useful part of it is what is inside its /www/tools
.
So, what I want to do is merge Bar's /www/tools
into Foo's /public/bar
, and pretend the rest of Bar's tree doesn't even exist.
Can do?
(I would suppose this is very similar to how you merge from a project that originally merged yours as a subtree. Which I don't know how to do, either.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我已经使用以下命令成功完成了此操作(根据您的场景重写)。
巨大警告!我仍在弄清楚如何从 Bar 中获取/合并。 这只会将所有内容引入一次。
我当前合并更改的方式如下:
这会给您留下冲突,说明大量文件已被删除,您只需
git rm
它们,然后git commit
。我当然愿意接受关于更好的改变方式的建议。
由于这是一个旧线程,我应该补充一点,我正在运行 Git 1.7.9。
I've successfully done this using the following commands (rewritten for your scenario).
HUGE WARNING! I'm still in the process of figuring out how to do fetch/merge from Bar. This will bring in everything just once.
My current way of merging changes is like so:
This will leave you with conflicts saying that a ton of files have been removed, you can just
git rm
them and thengit commit
.I'm certainly open to suggestions on a better way to pull changes.
Since this is an old thread, I should add that I'm running Git 1.7.9.
尝试使用 git 子树 来实现此目的。 它允许您将一个项目的子树提取到另一个项目中,然后您可以将其合并到您的项目中。
Try using git subtree for this. It allows you to extract a subtree of a project into another project, which you can then merge into yours.
编辑:我觉得你可以用 git merge --no-commit 来做到这一点。 这将尝试合并,即使不冲突,它也会在提交之前停止。 此时,您可以删除所有不需要的垃圾(包括在必要时恢复冲突的文件)并创建仅包含所需子树的合并提交。
原始答案:
您确实可以使用过滤器分支来实现此目的。 概述:
克隆源存储库:
使用裸克隆将节省您创建工作目录的时间和空间。
接下来,在克隆上使用filter-branch:
--all
让它知道您想要使用所有引用,而不仅仅是当前的HEAD。 您现在将拥有一个仅包含所需子目录以及与其关联的所有历史记录的存储库。注意:抱歉,我不知道有什么真正简单的方法可以删除除您想要的以外的所有内容。 您必须小心使用通配符,因为您不想破坏任何 git 目录。 这是可行的,尽管它比较慢,特别是如果您有很多文件:
无论如何,无论您如何管理要删除的文件列表,您都可以继续进行子树合并,从
bar_clone< 中提取/code> 到
foo
中。Edit: It occurs to me that you could do this just with
git merge --no-commit
. This will attempt the merge, and even if it does not conflict, it will stop just before committing. At this point you can remove all the junk you don't need (including restoring conflicted files if necessary) and create a merge commit only containing the desired subtree.Original answer:
You can indeed use filter-branch for this. An outline:
Clone your source repo:
Using a bare clone will save you the time and space of creating a working directory.
Next, use filter-branch on the clone:
The
--all
lets it know that you want to use all refs, not just the current HEAD. You will now have a repository containing only the desired subdirectory, and all of the history associated with it.Note: Sorry, I don't know a really straightforward way to remove all but what you want. You have to be careful with wildcards because you don't want to clobber any git directories. Here's something that'll work, though it's slower, especially if you've got a lot of files:
Anyway, however you manage the listing of files to remove, you can go ahead with your subtree merge, pulling from
bar_clone
intofoo
.我认为这本身不能通过合并来完成,但这些步骤可能会起作用,至少就最终产品而言是这样。 首先:
这会从 Bar 存储库中获取最新的提交,但不会尝试合并它们。 它在 .git/FETCH_HEAD 中记录了提交的 SHA
这显示了远程分支最新提交的 SHA 标识符是什么。
这将获取 www/tools 中文件的副本以获取提交并覆盖工作树中的内容。 然后,您可以像平常一样将这些更改提交到本地存储库。 生成的提交不会对它的来源有任何引用,但它至少应该让您的存储库包含您想要的文件版本。
I don't think this can be done using a merge, per-se, but these steps might do the trick, at least as far as the end product is concerned. First:
This fetches the latest commit(s) from the Bar repository, but doesn't try to merge them. It records the SHA for the commit in .git/FETCH_HEAD
This shows what the SHA identifier for the latest commit from the remote branch is.
This takes the copy of the files in www/tools for the fetched commit and overwrites what's in the working tree. You can then commit those changes to your local repository like normal. The resulting commit won't have any reference to where it came from, but it should at least get your repository with the versions of the files you want.
我建议使用子树两次 - 一次提取所有 /www/tools 一次提取 /public - 听起来 /public 应该在它自己的存储库中,所以我建议你将 /public 推送到一个新的存储库 - 使用它的所有子树历史记录,然后将 /www/tools 的子树历史记录合并到新的 /public 存储库中,并将其作为 Foo 的子树添加回来。
现在,您的存储库上有两个新分支。 一个包含公众的提交历史记录,另一个包含 www/tools。 从这里开始我将省略
cd
。创建新的公共存储库(我假设这里是 github,但听起来你可能想在本地进行)并将你的子树推送到那里:
git checkout 新共享公共
git push [电子邮件受保护]:my_id/new-shared-repo.git HEAD:master
然后将您的其他分支合并到其中:
虽然我已将
我们的
指定为提交策略,但它可能(可能)并不重要。最后,在执行合并并将其推送到新存储库后,返回到 Foo 存储库。 Git rm 那里的公共历史记录并将新的公共存储库添加为子树:
I would suggest using subtree twice - once to extract all of the /www/tools and once to extract /public - it sounds like /public should be in its own repo so, I would suggest you push /public to a new repo - with all of it's subtree history, then merge /www/tools's subtree history into the new /public repo and add that back as a subtree of Foo.
You now have two new branches on your repos. One with public's commit history and the other with www/tools. I'll omit
cd
from here on.Create your new public repo (I'm assuming github here but sounds like you might want to do it locally) and push your subtree there:
git checkout new-shared-public
git push [email protected]:my_id/new-shared-repo.git HEAD:master
Then merge your other branch into that:
Although I've specified
ours
as the commit policy, it probably (probably) doesn't matter.Finally, after you've preformed the merge and pushed it to the new repo, go back to the Foo repo. Git rm the public history from there and add the new public repo as a subtree: