只是一个现成的完整版本,基于@lucanLepus 接受的答案。
假设我是 userA,我想从 Github 上的存储库中从历史记录中完全删除文件夹 media/1 Juno-Trumpet/(在最近的提交中不再存在,但在很久以前的提交中)。
注意:此特定存储库具有原始分支 master、sfz 和 wifi,以及标记 v1.0。为了避免需要知道这一点,我在这里使用了一个镜像克隆(它创建了一个裸存储库,这很好,因为我将使用索引过滤器)。然后,由于这里是 GitHub,所以我先把所有的refs/pull/ refs 都扔了。
事实证明,这些文件也被命名为 media/Juno-Trumpet/ 和 media/Juno/,因此我们需要删除所有三个路径名。
git clone --mirror https://github.com/alexmacrae/SamplerBox.git
cd SamplerBox.git
git for-each-ref --format="git update-ref -d %(refname)" refs/pull | sh
git for-each-ref # to check that we have only wanted refs left
git count-objects -vH # size-pack: 54.40 MiB
git filter-branch --index-filter 'git rm -r --cached --ignore-unmatch "media/1 Juno-Trumpet" media/Juno-Trumpet media/Juno' --prune-empty --tag-name-filter cat -- --all
filter-branch 步骤需要一点时间,并以:
Ref 'refs/heads/master' was rewritten
Ref 'refs/heads/sfz' was rewritten
Ref 'refs/heads/wifi' was rewritten
WARNING: Ref 'refs/tags/v1.0' is unchanged
v1.0 -> v1.0 (7ec3254d08b65fd3ca8a048cef60b5b2c75f7e11 -> 7ec3254d08b65fd3ca8a048cef60b5b2c75f7e11)
(最后一行表示存储库中的一个标签位于任何重写的提交之前,即我们毕竟不需要--tag-name-filter cat。)
现在我们必须删除refs/original/ 名称。由于这是一个全新的克隆,因此没有过期的 reflog,但无论如何我们都会这样做,然后使用 git gc 重新打包:
git for-each-ref --format="git update-ref -d %(refname)" refs/original | sh
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git count-objects -vH # size-pack: 1.41 MiB
我还没有完成这最后一步:
git push origin '+refs/*:refs/*'
(如果您确实确定要完全清除所有媒体文件,则可能还需要清除所有拉取请求,因为否则它们会保留它们一段时间)。
顺便说一句,我找到了三个名称下的文件:
git cat-file --batch-all-objects --batch-check | sort +2 -rn | head
要查找比较大的文件,接着:
git rev-list --all | while read ref; do
git ls-tree -r $ref | grep 477145c7d0190f4e0aeea0f7bfb9accbf2c1ba48;
done | sort -u
(477145c7d0190f4e0aeea0f7bfb9accbf2c1ba48 是.wav 大文件之一。我没有检查删除的所有文件是否都是.wav 文件以及是否还有其他.wav 文件。)