我有一个 Git包含许多子目录的存储库。现在我发现其中一个子目录与另一个子目录无关,应该分离到一个单独的存储库。
如何在保持子目录中文件的历史记录的同时做到这一点?
我想我可以制作一个克隆并删除每个克隆不需要的部分,但我想这会在检查旧版本等时为我提供完整的树。这可能是可以接受的,但我更愿意能够假装两个存储库没有共享历史记录。
为了清楚起见,我有以下结构:
XYZ/
.git/
XY1/
ABC/
XY2/
但我想要这个:
XYZ/
.git/
XY1/
XY2/
ABC/
.git/
ABC/
最佳答案
更新 :这个过程非常普遍,所以 git 团队使用一个新工具,git subtree
使它变得更加简单。 .看这里:Detach (move) subdirectory into separate Git repository
您想克隆您的存储库,然后使用 git filter-branch
标记除您希望在新存储库中进行垃圾收集的子目录之外的所有内容。
git clone /XYZ /ABC
(注意:存储库将使用硬链接(hard link)克隆,但这不是问题,因为硬链接(hard link)文件本身不会被修改 - 将创建新文件。)
cd /ABC
for i in branch1 br2 br3; do git branch -t $i origin/$i; done
git remote rm origin
或者对于所有远程分支:
cd /ABC
for i in $(git branch -r | sed "s/.*origin\///"); do git branch -t $i origin/$i; done
git remote rm origin
WARNING: Ref 'refs/tags/v0.1' is unchanged
对于所有标签(因为它们都与子项目无关);此外,删除此类标签后,将回收更多空间。显然 git filter-branch
应该能够重写其他标签,但我无法验证这一点。如果要删除所有标签,请使用 git tag -l | xargs git tag -d
. --tag-name-filter cat --prune-empty
删除空提交并重写标签(请注意,这将不得不剥离它们的签名):git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC -- --all
或者,只重写 HEAD 分支并忽略标签和其他分支:
git filter-branch --tag-name-filter cat --prune-empty --subdirectory-filter ABC HEAD
git reset --hard
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
git reflog expire --expire=now --all
git gc --aggressive --prune=now
现在您拥有 ABC 子目录的本地 git 存储库,并保留了其所有历史记录。
注意:对于大多数用途,
git filter-branch
确实应该添加参数 -- --all
.是的,这真的是--space-- all
.这需要是命令的最后一个参数。正如 Matli 发现的那样,这将保留项目分支和标签包含在新的存储库中。编辑:整合了来自以下评论的各种建议,以确保例如存储库实际上缩小了(以前并非总是如此)。
关于git - 将子目录分离(移动)到单独的 Git 存储库中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/696043/