14

我有遥控器 Foo 和 Bar。Foo 是一个有很多目录的 Web 应用程序,其中相关的是/public包含各种文件和其他目录。

Bar 是一组库,没有在前端使用,因此,它应该/public/bar放在 Foo 中。Foo 那里没有文件。

无论是子模块还是子树合并,这都是小菜一碟。不过……</p>

Bar 的树很乱,它有各种预制作文件,如 PSD 和 FLA,其中唯一真正有用的部分是/www/tools.

所以,我想做的是将 Bar's 合并/www/tools到 Foo's/public/bar中,并假装 Bar 树的其余部分甚至不存在。

可以做?

(我想这与您从最初将您的项目合并为子树的项目合并的方式非常相似。我也不知道该怎么做。)

4

5 回答 5

11

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

$ 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。

于 2012-08-21T03:43:19.370 回答
4

尝试为此使用git subtree。它允许您将项目的子树提取到另一个项目中,然后您可以将其合并到您的项目中。

于 2009-08-20T18:23:22.310 回答
2

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

原答案:

您确实可以为此使用 filter-branch 。一篇大纲:

克隆您的源代码库:

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让它知道你想使用所有的 refs,而不仅仅是当前的 HEAD 。您现在将拥有一个仅包含所需子目录以及与其关联的所有历史记录的存储库。

注意:对不起,我不知道一个真正简单的方法来删除除你想要的之外的所有内容。您必须小心使用通配符,因为您不想破坏任何 git 目录。这里有一些可行的方法,虽然速度较慢,特别是如果你有很多文件:

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

无论如何,无论您如何管理要删除的文件列表,您都可以继续进行子树合并,bar_clonefoo.

于 2009-07-28T19:30:24.947 回答
0

我认为这不能使用合并本身来完成,但这些步骤可能会奏效,至少就最终产品而言。第一的:

% 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 中的文件副本用于获取的提交,并覆盖工作树中的内容。然后,您可以像往常一样将这些更改提交到本地存储库。生成的提交不会对它的来源有任何引用,但它至少应该让你的存储库包含你想要的文件版本。

于 2009-07-23T21:27:05.937 回答
0

我建议使用 subtree 两次——一次提取所有 /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 new-shared-public git push git@github.com:my_id/new-shared- repo.git 头:主

然后将您的另一个分支合并到该分支中:

git checkout new-shared-www-tools
git remote add Foo git@github.com:my_id/new-shared-repo.git
git merge -s ours --no-commit Bar/master

虽然我已经指定ours了提交策略,但它可能(可能)并不重要。

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

git subtree add --squash --prefix shared git@github.com:my_id/new-shared-repo.git master
git subtree pull --squash --prefix shared git@github.com:my_id/new-shared-repo.git master
git push
于 2012-10-25T14:28:24.700 回答