我有一个Git存储库,其中包含许多子目录。现在我发现其中一个子目录与另一个子目录无关,应该分离到一个单独的存储库中。

如何在保留子目录中文件的历史记录的同时执行此操作?

我想我可以制作一个克隆并删除每个克隆中不需要的部分,但我想这会在检查旧版本等时提供完整的树。这可能是可以接受的,但我更希望能够假装这两个存储库没有共享的历史。

为了清楚起见,我有以下结构:

XYZ/
    .git/
    XY1/
    ABC/
    XY2/

但我想改为:

XYZ/
    .git/
    XY1/
    XY2/
ABC/
    .git/
    ABC/

当前回答

更简单的方法

安装git拆分。我基于jkeating的解决方案将其创建为git扩展。将目录拆分为本地分支#更改到回购的目录cd/path/to/repo#检查分支机构数字结帐XYZ#将多个目录拆分为新的分支XYZ数字拆分-b XYZ XY1 XY2在某处创建空回购。我们假设在GitHub上创建了一个名为xyz的空repo,其路径为:git@github.com:simpliwp/xyz.git推送至新回购。#为空回购添加一个新的远程源,以便我们可以在GitHub上推送到空回购git远程添加origin_xyzgit@github.com:simpliwp/xyz.git#将分支推送到空回购的主分支git push origin_xyz xyz:master将新创建的远程存储库克隆到新的本地目录#将当前目录更改为旧的存储库cd/path/to/where/you/want/the/new/local/repo#克隆您刚刚推送到的远程存储库git克隆git@github.com:simpliwp/xyz.git

其他回答

值得一提的是,下面是如何在Windows机器上使用GitHub。假设您在C:\dir1中有一个克隆的repo。目录结构如下:C:\dir1\dir2\dir3。dir3目录是我希望成为一个新的独立存储库的目录。

github:

创建新存储库:MyTeam/mynewrepo

猛击提示:

$cd c:/Dir1$gitfilter分支--修剪空--子目录筛选器dir2/dir3 HEAD返回:Ref“refs/heads/master”已重写(fyi:dir2/dir3区分大小写。)$git远程添加some_namegit@github.com:我的团队/mynewrepo.gitgit远程添加原点等不起作用,返回“远程原点已存在”$git push--进度some_name master

这不再那么复杂,您只需在repo的克隆上使用gitfilter branch命令,即可选择不需要的子目录,然后推送到新的远程。

git filter-branch --prune-empty --subdirectory-filter <YOUR_SUBDIR_TO_KEEP> master
git push <MY_NEW_REMOTE_URL> -f .

您可以轻松尝试https://help.github.com/enterprise/2.15/user/articles/splitting-a-subfolder-out-into-a-new-repository/

这对我有用。我在上面给出的步骤中遇到的问题是

在此命令中,gitfilter branch--prune empty--子目录筛选器FOLDER-NAME branch-NAMEBRANCH-NAME是主如果由于保护问题提交时最后一步失败,请遵循以下步骤:https://docs.gitlab.com/ee/user/project/protected_branches.html

如上所述,我必须使用相反的解决方案(删除所有提交而不触及我的dir/subdr/targetdir),这似乎可以很好地去除大约95%的提交(根据需要)。然而,还有两个小问题。

首先,过滤器分支完成了一项出色的工作,删除了引入或修改代码的提交,但显然,合并提交在Gitiverse的站点之下。

截图:合并疯狂!

这是一个我可能可以忍受的美容问题(他说……慢慢后退,眼睛转向)。

第二,剩下的几个提交几乎都是重复的!我似乎获得了第二个多余的时间线,它几乎涵盖了整个项目的历史。有趣的是(你可以从下面的图片中看到),我的三个本地分支并不都在同一个时间线上(这就是为什么它存在,而不仅仅是垃圾收集)。

尖叫:双双,Git过滤器分支样式

我唯一能想到的是,其中一个被删除的提交可能是过滤器分支实际删除的单个合并提交,并且创建了并行时间线,因为每个现在未合并的链都有自己的提交副本。(耸耸肩,我的TARDiS在哪里?)我很确定我能解决这个问题,尽管我真的很想知道它是怎么发生的。

对于疯狂的mergefest-O-RAMA,我很可能会把它单独放在一边,因为它在我的承诺历史中根深蒂固,每当我走近时,它都会威胁我——它似乎并没有真正引起任何非外观问题,因为在Tower.app中它非常漂亮。

查看git_split项目https://github.com/vangorra/git_split

在自己的位置将git目录转换为自己的存储库。没有子树有趣的业务。该脚本将获取git存储库中的现有目录,并将该目录转换为独立的存储库。在此过程中,它将复制您提供的目录的整个更改历史记录。

./git_split.sh <src_repo> <src_branch> <relative_dir_path> <dest_repo>
        src_repo  - The source repo to pull from.
        src_branch - The branch of the source repo to pull from. (usually master)
        relative_dir_path   - Relative path of the directory in the source repo to split.
        dest_repo - The repo to push to.