将子目录从Git repo复制到新的存储库中(使用新的目录结构)

将子目录从Git repo复制到新的存储库中(使用新的目录结构),git,Git,这个问题是基于 我的存储库结构如下所示: /apps /AAA /BBB /CCC /libs /XXX /YYY /ZZZ 而我希望这样: /AAA /XXX 链接问题中建议的解决方案保留文件夹的原始路径。相反,我想在一个新的存储库中提取一组位于不同路径的文件夹,其中所有文件夹都位于根目录下 另一个限制是,提交历史可能同时涉及两个文件夹,我希望以相同的方式保留。例如,假设原始存储库中的日志包含: "My commit message" /apps/AAA/file1

这个问题是基于

我的存储库结构如下所示:

/apps
  /AAA
  /BBB
  /CCC
/libs
  /XXX
  /YYY
  /ZZZ
而我希望这样:

/AAA
/XXX
链接问题中建议的解决方案保留文件夹的原始路径。相反,我想在一个新的存储库中提取一组位于不同路径的文件夹,其中所有文件夹都位于根目录下

另一个限制是,提交历史可能同时涉及两个文件夹,我希望以相同的方式保留。例如,假设原始存储库中的日志包含:

"My commit message"
/apps/AAA/file1.txt
/libs/XXX/file2.txt
我希望在新回购协议中看到同等内容:

"My commit message"
/AAA/file1.txt
/XXX/file2.txt

如何做到这一点?

其中棘手的部分是历史保存。可以使用
git过滤器分支
完成

您几乎可以使用
子目录过滤器
,但一次只能处理一个目录(因此这会很棘手),并且影响多个目录的任何提交都不会在结果中很好地表示

相反,您需要使用
树过滤器
,不幸的是,这意味着该过程可能需要相当长的时间才能运行。基本上,该过程将签出每个提交(包括编写工作树),运行筛选脚本(它将移动您想要的目录并删除所有其他内容),然后提交结果。您可能希望在快速存储上运行此功能—如果有很多历史记录,那么即使是RAMDisk也不会有过大的杀伤力

过滤器脚本的确切外观在某种程度上取决于您将运行的环境;但是bash中的示例filter.sh可能如下所示

#! /bin/bash

mv apps/AAA .
mv libs/XXX .
rm -r apps libs
然后你就跑

git filter-branch --tree-filter filter.sh --prune-empty
这会创建一些“备份参考”(例如,
原件/refs/heads/master
),您需要对其进行清理


删除这些引用后,原始提交仍在回购中。如果您想摆脱它们,最干净的方法是克隆(如果在本地执行,则使用
文件://
url)。

我通过以下方式修复了我的问题:

1) 使用以下命令从原始回购中拆分子回购:

2) 使用命令将文件夹移动到新路径(以便保留历史记录):

3) 将分行推至新的回购协议

git push ../new_repo/ +tmp_branch:master
或者,如果您正在使用GitHub:

git push git@github.com:accountname/new_repo +tmp_branch:master
git push ../new_repo/ +tmp_branch:master
git push git@github.com:accountname/new_repo +tmp_branch:master