如何在维护历史记录的同时将单个目录从git存储库移至新存储库?


110

我继承了一个git仓库,在单独的目录中包含多个项目。我想将存储库拆分为新的单个存储库,每个项目一个,然后让主存储库将项目作为子模块包含。我想做所有这一切,同时尽可能保留各个项目的修订历史。

我可以为每个项目克隆存储库,并每次都删除所有其他项目,但是有更好的方法来避免在每个新项目存储库中都有克隆的历史记录吗?


2
添加了git-submodules标记,因为这对于将部分回购转换为子模块非常有用。
idbrii

Answers:


99

您可以git filter-branch用来重写项目的历史记录。从文档中:

要重写存储库,使其看起来好像foodir /已经是其项目根,并丢弃所有其他历史记录:

git filter-branch --subdirectory-filter foodir -- --all

为您的存储库制作几份副本,对要拆分的每个子目录执行此操作,然后最后找到所需的内容。


1
如果我想排除 foodir,并删除所有历史记录怎么办?
saeedgnu

1
注意:如果需要多个目录,则需要指定--subdirectory-filter多次。EG git filter-branch --subdirectory-filter foodir --subdirectory-filter bardir--subdirectory不会取多个Dirs,但可以多次指定。
EnabrenTane 2013年

3
@Adam如果您想保留foodir原始项目中的历史记录,而不重写其历史记录,git rm -r foodir那么就足够了(这也将删除工作树中的副本;如果您不想这样做,请使用--cached)。如果您想将其从历史记录中完全删除(也回答@ilius的问题),则需要类似git filter-branch --index-filter 'git rm -r --cached --ignore-unmatched foodir' -- --all
Brian Campbell

2
@ilius对不起,我之前错过了您的问题,请参见上面的答复,以获取有关如何删除目录及其历史记录的答案。
Brian Campbell

2
@ilius是的,也可以。对于大型项目,该--index-filter解决方案比的解决方案要快--tree-filter,因为它不必实际检出文件,它可以直接操作索引。该--tree-filter可以轻松一点不过用,因为你可以使用普通的filsystem操作,而不必与索引处理操作的工作。
Brian Campbell

4

要将文件夹导出为新存储库,您需要:

  1. 在要导出文件夹的位置克隆存储库。
  2. 要在托管提供商(如GitHub)上创建一个空存储库,以存储导出的文件夹。
  3. 打开克隆的存储库文件夹并运行以下命令:

    git subtree push --prefix=YourFolderNameToExport https://github.com/YourUserName/YourNewCleanRepoName master
    

1
git subtree不能作为Cygwin软件包提供。如果您需要它:stackoverflow.com/a/27116828/2484903
Jack Miller

2

git的要点是,通过哈希父提交将历史记录体现在每个提交中。您可以将提交(重播)(实质上是svn-importer的工作方式)“重播”到新的存储库中,并且仅保留每个子项目。但是,这将破坏提交哈希的含义。如果您对此没有问题,那就去吧。

过去,我只是克隆它并继续前进。这使事情变大了,但是磁盘空间却很便宜。我的时间很昂贵。

我也不知道有什么工具可以拼接目录。我想您可以在目录上进行git-log查找所有提交,然后使用git-fast-export之类的内容重播提交?


我upvoted因为这一点,因为不值得为负值-我肯定不会按照这个方法,但可以看出他在努力
艾文
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.