git:我可以子树合并存储库的子路径吗?

发布于 2024-07-29 03:39:35 字数 481 浏览 8 评论 0原文

我有遥控器 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

千紇 2024-08-05 03:39:35

我已经使用以下命令成功完成了此操作(根据您的场景重写)。

$ git remote add Bar /path/to/bar
$ git merge -s ours --no-commit Bar/master
$ git read-tree --prefix=public/bar -u Bar/master:www/tools/

巨大警告!我仍在弄清楚如何从 Bar 中获取/合并。 这只会将所有内容引入一次。

我当前合并更改的方式如下:

$ get fetch Bar
$ git pull -X subtree=public/bar Bar master

这会给您留下冲突,说明大量文件已被删除,您只需 git rm 它们,然后 git commit

我当然愿意接受关于更好的改变方式的建议。

由于这是一个旧线程,我应该补充一点,我正在运行 Git 1.7.9。

I've successfully done this using the following commands (rewritten for your scenario).

$ git remote add Bar /path/to/bar
$ git merge -s ours --no-commit Bar/master
$ git read-tree --prefix=public/bar -u Bar/master:www/tools/

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:

$ get fetch Bar
$ git pull -X subtree=public/bar Bar master

This will leave you with conflicts saying that a ton of files have been removed, you can just git rm them and then git 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.

胡大本事 2024-08-05 03:39:35

尝试使用 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.

狼亦尘 2024-08-05 03:39:35

编辑:我觉得你可以用 git merge --no-commit 来做到这一点。 这将尝试合并,即使不冲突,它也会在提交之前停止。 此时,您可以删除所有不需要的垃圾(包括在必要时恢复冲突的文件)并创建仅包含所需子树的合并提交。

原始答案:

您确实可以使用过滤器分支来实现此目的。 概述:

克隆源存储库:

git clone --bare /path/to/bar /path/to/bar_clone

使用裸克隆将节省您创建工作目录的时间和空间。

接下来,在克隆上使用filter-branch:

git filter-branch --index-filter 'git rm -rf <unwanted files/directories>' -- --all

--all让它知道您想要使用所有引用,而不仅仅是当前的HEAD。 您现在将拥有一个仅包含所需子目录以及与其关联的所有历史记录的存储库。

注意:抱歉,我不知道有什么真正简单的方法可以删除除您想要的以外的所有内容。 您必须小心使用通配符,因为您不想破坏任何 git 目录。 这是可行的,尽管它比较慢,特别是如果您有很多文件:

git filter-branch --index-filter 'git rm -f `git ls-files | grep -v ^www/tools`' -- --all

无论如何,无论您如何管理要删除的文件列表,您都可以继续进行子树合并,从 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:

git clone --bare /path/to/bar /path/to/bar_clone

Using a bare clone will save you the time and space of creating a working directory.

Next, use filter-branch on the clone:

git filter-branch --index-filter 'git rm -rf <unwanted files/directories>' -- --all

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:

git filter-branch --index-filter 'git rm -f `git ls-files | grep -v ^www/tools`' -- --all

Anyway, however you manage the listing of files to remove, you can go ahead with your subtree merge, pulling from bar_clone into foo.

晨与橙与城 2024-08-05 03:39:35

我认为这本身不能通过合并来完成,但这些步骤可能会起作用,至少就最终产品而言是这样。 首先:

% git fetch Bar

这会从 Bar 存储库中获取最新的提交,但不会尝试合并它们。 它在 .git/FETCH_HEAD 中记录了提交的 SHA

% cat .git/FETCH_HEAD
b91040363160aab4b5dd46e61e42092db74b65b7                branch 'Bar' of ssh://blah...

这显示了远程分支最新提交的 SHA 标识符是什么。

% git checkout b91040363160aab4b5dd46e61e42092db74b65b7 www/tools

这将获取 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:

% git fetch Bar

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

% cat .git/FETCH_HEAD
b91040363160aab4b5dd46e61e42092db74b65b7                branch 'Bar' of ssh://blah...

This shows what the SHA identifier for the latest commit from the remote branch is.

% git checkout b91040363160aab4b5dd46e61e42092db74b65b7 www/tools

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.

饮惑 2024-08-05 03:39:35

我建议使用子树两次 - 一次提取所有 /www/tools 一次提取 /public - 听起来 /public 应该在它自己的存储库中,所以我建议你将 /public 推送到一个新的存储库 - 使用它的所有子树历史记录,然后将 /www/tools 的子树历史记录合并到新的 /public 存储库中,并将其作为 Foo 的子树添加回来。

cd foo
git subtree split --prefix=public --branch=new-shared-public --annotate='(split) '
cd../bar
git subtree split --prefix=www/tools --rejoin --branch=new-shared-www-tools --annotate='(split) '

现在,您的存储库上有两个新分支。 一个包含公众的提交历史记录,另一个包含 www/tools。 从这里开始我将省略cd

创建新的公共存储库(我假设这里是 github,但听起来你可能想在本地进行)并将你的子树推送到那里:
git checkout 新共享公共
git push [电子邮件受保护]:my_id/new-shared-repo.git HEAD:master

然后将您的其他分支合并到其中:

git checkout new-shared-www-tools
git remote add Foo [email protected]:my_id/new-shared-repo.git
git merge -s ours --no-commit Bar/master

虽然我已将我们的指定为提交策略,但它可能(可能)并不重要。

最后,在执行合并并将其推送到新存储库后,返回到 Foo 存储库。 Git rm 那里的公共历史记录并将新的公共存储库添加为子树:

git subtree add --squash --prefix shared [email protected]:my_id/new-shared-repo.git master
git subtree pull --squash --prefix shared [email protected]:my_id/new-shared-repo.git master
git push

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.

cd foo
git subtree split --prefix=public --branch=new-shared-public --annotate='(split) '
cd../bar
git subtree split --prefix=www/tools --rejoin --branch=new-shared-www-tools --annotate='(split) '

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:

git checkout new-shared-www-tools
git remote add Foo [email protected]:my_id/new-shared-repo.git
git merge -s ours --no-commit Bar/master

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:

git subtree add --squash --prefix shared [email protected]:my_id/new-shared-repo.git master
git subtree pull --squash --prefix shared [email protected]:my_id/new-shared-repo.git master
git push
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文