如何删除以前添加的git子树及其历史记录

时间:2014-09-29 19:54:47

标签: git git-subtree

很多以前我在我的git存储库中添加了一个子树。该子树包含多个文件夹和文件。我添加了子树而不是创建子模块(如推荐的那样)。现在我意识到我只想要子树中的一个文件,而不是其他文件。更糟糕的是,当其他clone我的存储库,他们获得的不是预期的 - 与我创建的子树和其他代码存在一些冲突。

我可以通过

获取文件/文件夹
git rm subtree–folder1 subtree_folder2 subtree_files.*
然而,我仍然从子树中留下了冗长的提交历史。

由于我最初添加了子树并且无法丢失我生成的提交历史记录,因此我做了大量的开发。

简而言之,这就是我想要的:

  1. 删除所有子树文件/文件夹。
  2. 忘记所有子树提交的历史记录。
  3. 只留下我的代码和我的历史。
  4. 这可能吗?

    PS。一个可能的复杂因素是我将我希望保留的单个头文件从子树移到我代码中的某个文件夹。我希望这不是让我忘记子树历史的原因。

    尝试

    从远程服务器重新结帐后,我有以下内容:

    $ ls
    .git             CMakeLists.txt   Read.cpp         logging.conf
    .gitignore       ENDF6            TestData         src
    .sparse-checkout LICENCE          doc              test
    .travis.yml      README.md        include          tools
    

    .gitignore只有:     建立/     调试/

    当我按照建议尝试命令时,我没有得到非常满意的答复:

    $ git filter-branch --index-filter 'git rm --cached -rf test tools src doc LICENCE README.md .travis.yml' HEAD
    Rewrite 2fec85e41e40ae18efd1b130f55b14166a422c7f (1/1701)fatal: pathspec 'test' did not match any files
    index filter failed: git rm --cached -rf test tools src doc LICENCE README.md .travis.yml
    

    我不确定为什么它显然存在test时出现问题。我感到困惑。

2 个答案:

答案 0 :(得分:17)

您需要使用filter-branch和--prune-empty选项来删除任何不再引入新更改的提交。

git filter-branch --index-filter 'git rm --cached --ignore-unmatch -rf dir1 dir2 dirN file1 file2 fileN' --prune-empty -f HEAD

之后,如果要恢复磁盘空间,则需要删除过滤分支保存的所有原始引用,使reflog过期,以及垃圾回收。

答案 1 :(得分:2)

您可以使用git filter-branch将操作应用于您在分支中进行的所有提交。这包括在重写整个历史记录时从每个提交中删除文件。这里有一个很好的描述和说明:http://gitready.com/beginner/2009/03/06/ignoring-doesnt-remove-a-file.html。您可能会发现以下问题也很有用:Completely remove files from Git repo and remote on GitHub(这是我找到链接的地方)。您将使用此解决方案运行的实际命令将类似于git filter-branch --index-filter 'git rm --cached -rf subtree–folder1 subtree_folder2' HEAD

另一种方式,对你正在做的事情来说可能有点过分,就是挑选。 Cherry-picking允许您根据自己喜欢的任何详细程度重写您喜欢的历史记录的任何部分:http://git-scm.com/docs/git-cherry-pick。您需要执行git reset --hard <HASH of commit that introduced the subtree>之类的操作,然后执行一系列

git cherry-pick -n <following commit hashes>
git reset
git add -p
git commit

对于您所做的每个后续提交。这将允许您从过去的每个提交中删除子树。有关有效挑选樱桃的更多信息,请参阅partly cherry-picking a commit with git。完成此版本的删除操作后,您将需要删除不再属于您的分支的旧提交:

git reflog expire --expire-unreachable=now --all
git gc --prune=now

其他参考问题: How to move a branch backwards in git? Listing and deleting Git commits that are under no branch (dangling?)