很多以前我在我的git
存储库中添加了一个子树。该子树包含多个文件夹和文件。我添加了子树而不是创建子模块(如推荐的那样)。现在我意识到我只想要子树中的一个文件,而不是其他文件。更糟糕的是,当其他clone
我的存储库,他们获得的不是预期的 - 与我创建的子树和其他代码存在一些冲突。
我可以通过
获取文件/文件夹git rm subtree–folder1 subtree_folder2 subtree_files.*
然而,我仍然从子树中留下了冗长的提交历史。
由于我最初添加了子树并且无法丢失我生成的提交历史记录,因此我做了大量的开发。
简而言之,这就是我想要的:
这可能吗?
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
时出现问题。我感到困惑。
答案 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?)