使用git-filter-branch命令提取多个目录

27

我有一个大代码仓库,目前包含多个顶级子文件夹中的项目,比如 /a/b/c/d

现在我想把这个仓库分成两个不同的仓库:一个包含 /a/b,另一个包含 /c/d

我知道可以使用 git filter-branch --subdirectory-filter 提取单个目录,但似乎无法一次提取多个目录。

我也知道可以使用 git filter-branch --prune-empty --tree-filter 删除除两个目标目录以外的所有内容。但这样做感觉不太对,因为我需要手动指定可能存在的所有顶级目录。

是否有更好的方法从大型代码库中提取两个目录?

PS:当然,任何使用除 git filter-branch 之外的其他工具的好的解决方案都可以接受。;)


1
可能是 https://dev59.com/8W865IYBdhLWcg3wQMID 的重复问题。 - michas
可能是将许多子目录分离到一个新的、独立的Git存储库中的重复问题。 - Michael Freidgeim
现在应该接受git filter-repo的答案,因为它比git filter-branch更易于使用和更安全。 - CharlesB
4个回答

49

使用

git filter-branch -f --prune-empty --tree-filter 'bash preserve-only.sh a b' -- --all

其中 preserve-only.sh 是:

IFS=':'
GLOBIGNORE="$*"
rm -rf *

这应该会从所有分支的所有提交中删除除ab以外的所有内容,这应该与精确提取给定目录相同。

要完成实际的拆分,您可以使用类似于rm -rf a b的筛选器来获取在第一次运行中未提取的所有更改。


更新:在尝试使用--index-filter加快速度时,我找到了一个更简单的解决方案:

git filter-branch -f --prune-empty --index-filter \
  'git rm --cached -r -q -- . ; git reset -q $GIT_COMMIT -- a b' -- --all

这只是删除所有内容,然后恢复给定的目录。


3
目前来看,索引过滤选项是最好的选择。一个建议是,在git rm语句中添加--ignore-unmatch以取消错误,当.没有匹配任何内容时(提交后存储库为空)会出现该错误。 - vmrob
太棒了,正是我在寻找的。它还可以处理嵌套目录。谢谢! - thaddeusmt
对于标签,我添加了 --tag-name-filter cat - P.J.Meisch
1
可能应该更加强调使用“index-filter”的第二个选项。由于我的注意力不够集中,我只是从第一个命令开始阅读,然后就停下来了。对于我们的大型代码库,这将需要数小时才能完成。幸运的是,我回到这个帖子,发现了“更新”,它只用了几秒钟就完成了。 - qqilihq
1
这个答案已经过时了,现在更倾向于使用 git filter-repo 方法,请参见下面 @Cem.S 的答案! - CharlesB
显示剩余2条评论

8

在搜索并尝试了提出的解决方案后,现在推荐使用 git-filter-repo 来进行操作(请参见此处)。

git filter-repo --path a --path b

目前在Windows上安装它存在一些问题,但是一旦安装完成,它的工作非常好且简单。 - Tomasz Chudzik

0

对于这个问题,我不知道比tree-filter更好的方法。所以你已经拥有了所有需要的信息。现在就去做吧!

首先创建你的两个分支:

git branch br1
git branch br2

现在对于每个分支,检查它,然后使用tree-filter进行过滤。

然后,您可以通过推送它们或克隆或拉取它们来将它们拆分到单独的目录中。


0

我更喜欢这个

git filter-branch -f --prune-empty --tree-filter "ls -I a -I b | xargs rm -rf"  -- --all

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接