简短回答
git filter-branch
提供了您所需的功能。使用--subdirectory-filter
选项,您可以创建一个新的提交集,其中subDirectory
的内容位于目录的根目录下。
git filter-branch --prune-empty --subdirectory-filter subDirectory -- --branches
步骤
以下是以安全的方式执行此操作的示例。您需要为每个将被隔离到自己的存储库中的子目录执行此操作,在本例中为dir1
。
首先,克隆您的存储库以保持更改的隔离:
git clone yourRemote dir1Clone
cd dir1Clone
为了准备克隆的代码库,我们将重新创建所有远程分支作为本地分支。我们跳过以
*
开头的那个分支,因为那是当前的分支,在这种情况下会显示
(no branch)
,因为我们处于无头状态:
为了准备克隆的代码库,我们将把所有远程分支重新创建为本地分支。我们跳过以*
开头的分支,因为它是当前分支,在这种情况下会显示(no branch)
,因为我们处于无头状态:
git checkout --detach
git branch | grep --invert-match "*" | xargs git branch -D
为了在本地重新创建所有远程分支,我们通过执行
git branch --remotes
命令的结果进行操作。我们跳过包含
->
的分支,因为它们不是实际的分支:
要在本地重新创建所有远程分支,我们需要查看 git branch --remotes
的输出结果。但我们会跳过其中包含->
的内容,因为这些不是真正的分支:
git branch --remotes --no-color | grep --invert-match "\->" | while read remote; do
git checkout --track "$remote"
done
git remote remove origin
最后运行filter-branch
命令。这将创建新的提交,其中包含所有涉及dir1
子目录的提交。同时还会更新涉及该子目录的所有分支。输出将列出所有未更新的引用,对于根本没有涉及dir1
的分支来说,就是这种情况。
# Isolate dir1 and recreate branches
# --prune-empty removes all commits that do not modify dir1
# -- --all updates all existing references, which is all existing branches
git filter-branch --prune-empty --subdirectory-filter dir1 -- --all
完成后,您将获得一组新的提交,其中根据库的根目录为dir1
。只需添加您的远程分支以推送新的提交,或将其用作全新的存储库。
如果您关心存储库的大小,可以将以下步骤作为最后一步:
即使所有分支都已更新,您的存储库仍将保留原始存储库的所有对象,尽管只能通过引用日志访问。如果要删除这些内容,请阅读如何清除Git中无用的提交
一些其他资源:
-- --all
选项应该迁移两个分支和标签。如果你只想要标签,那么-- --tags
选项是存在的。请记住,如果您正在为未迁移的提交打标签(例如,如果它从未触及子目录中的文件),则会打印警告并将标签留在原地。 - Maic López Sáenz