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

时间:2009-07-23 20:40:35

标签: git merge version-control subtree

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

Bar是一组库,在前端使用了什么,因此,它应该在Foo中的/public/bar中。 Foo没有文件。

无论子模块还是子树合并,这都是小菜一碟。然而...

Bar的树很乱,它有各种各样的预生产文件,比如PSD和FLA,唯一真正有用的部分就是/www/tools里面的内容。

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

可以吗?

(我认为这与你最初将你的项目合并为子树的项目非常类似。我不知道该怎么做。)

5 个答案:

答案 0 :(得分: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。

答案 1 :(得分:4)

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

答案 2 :(得分: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让它知道您想要使用所有引用,而不仅仅是当前的HEAD。您现在将拥有一个仅包含所需子目录的存储库,以及与之关联的所有历史记录。

注意:抱歉,我不知道一种非常简单的方法可以删除除了你想要的所有东西。你必须小心使用通配符,因为你不想破坏任何git目录。这里的东西会起作用,虽然速度较慢,特别是如果你有很多文件:

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

无论如何,无论您管理要删除的文件列表,都可以继续进行子树合并,从bar_clone拉入foo

答案 3 :(得分: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中用于获取提交的文件的副本,并覆盖工作树中的内容。然后,您可以像平常一样将这些更改提交到本地存储库。生成的提交将不会引用它的来源,但至少应该使用所需文件的版本获取存储库。

答案 4 :(得分:0)

我建议使用子树两次 - 一次提取所有的/ www /工具,一次提取/公开 - 听起来像/ public应该在自己的repo中所以,我建议你推送/公开一个新的repo - 包含所有子树的历史记录,然后将/ www / tools的子树历史合并到新的/公共repo中,并将其作为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 HEAD:master

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

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