从历史记录中删除不需要的文件,包括使用filter-branch的所有引用。

3
近期,我克隆了一个SVN代码库,其中包含一些不再需要的二进制文件。遗憾的是,我已经将其带有这些二进制文件的版本推送到了Github。现在,我想使用'git filter-branch'移除这些文件,但是在处理标签和分支时遇到了一些问题。
基本上,我创建了一个简单的shell脚本来删除由以下命令确定的文件列表:
git rev-list --objects --all | grep .jar > files.txt

删除脚本如下:

#!/bin/sh
while read file_hash file_to_remove
do
    echo "Removing "$file_to_remove;
    git filter-branch --index-filter "git rm --cached --ignore-unmatch $file_to_remove"
    rm -rf .git/refs/original/;
    git reflog expire --all --expire-unreachable=0;
    git repack -A -d;
    git prune
done < $1

我有一些标签(全部列在.git/packed-refs中),其中一个是.git/refs/remotes/origin(指向Github repo)。使用上述脚本删除文件没有想要的效果('du -cm'仍然输出相同的大小;'git rev-list'仍然列出这些文件),直到我手动从.git/packed-refs和.git/refs/remotes/origin目录中删除所有引用。
当然,这种方法会丢失所有标签以及将本地更改推回Github的可能性。是否有我忽略的内容或者有其他方法可以删除所有分支/标签中的文件而不破坏我的历史记录呢?
非常感谢, Matthes
1个回答

7
我最终使用了 BFG Repo Cleaner 来处理一个裸克隆库(git clone --mirror repo-url)。它会遍历每个分支/标签,使其正常工作,而且比 filter-branch 更快。希望这能帮助其他遇到类似问题的人。
以下是我的包装脚本:
#!/bin/bash
#usage: ./remove_files.sh file_list.txt bare-repo-dir
while read file_hash file_to_remove
do
    echo "Removing "$file_to_remove;
    lastFile=`echo $file_to_remove | awk -F/ '{print $NF}'`;
    java -jar bfg.jar --delete-files $lastFile $2;
done < $1

cd $2;
git gc --prune=now --aggressive;
cd ..;

1
非常高兴您喜欢这个工具@matthes!出于好奇,您需要删除多少个不同的文件?“--delete-files”开关接受glob表达式,通常最好只运行一次The BFG。例如:'--delete-files *.{xml,exe}' - Roberto Tyley
@Roberto:好提示。事实上,最后我只是从仓库中删除了(一大堆).jar文件。所以我想通过“--delete-files *.jar”执行会更快(而且更安全?)。 - matthes
没错," --delete-files *.jar "就能解决问题!(或者选择一些类似于“--strip-blobs-bigger-than 512K”的方案)。BFG 还会更新提交消息中找到的所有提交 ID,因此最好只进行一次操作。无论采用哪种方法,BFG 都会确保不删除最新提交中的任何内容,因此仍在使用的任何 jar 文件都不会被删除。 - Roberto Tyley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接