从git repo的历史记录中删除文件夹并不会使repo变小

时间:2017-05-19 10:42:38

标签: git github

我阅读了许多相关问题,但我遇到了以下问题。

this repo中,media/1 Juno-Trumpet中有大型文件(在之前的提交中),因此我完全按照answer here删除了这些文件:

git clone https://github.com/alexmacrae/SamplerBox.git
git count-objects -vH

总文件大小:54MB

git filter-branch --tree-filter 'rm -rf "media/1 Juno-Trumpet"' --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo "media/1 Juno-Trumpet/" >> .gitignore
git add .gitignore
git commit -m 'Removing a folder from git history'
git gc
git count-objects -vH

总文件大小:54MB

问题:为什么回购邮件的尺寸没有变化?如何在清理后使回购尺寸变小?

3 个答案:

答案 0 :(得分:3)

运行git filter-branch实际上复制每次过滤的提交。生成的存储库从不任何小型井,而不是尚未 - 通常更大。如果您幸运或聪明,大多数副本会重复使用大多数原始对象,因此生成的存储库只比原始存储库大一点

您可能会合理地问:"那么我们为什么要过滤存储库?"事实上,对于每个使用存储库的人来说,大多数情况下你不应该:它是一个非常令人头痛的问题(但通常只是一次性的,至少一次),因为他们都必须切换到新的过滤存储库。但真正的答案是,在过滤之后,您可以删除原始(预复制)对象的引用,或者将存储库克隆到新的新克隆。

原始物品'引用保存在refs/original/ 中的reflogs中(特别是HEAD reflog通常会有它们)。如果您选择(出于某些疯狂的原因)不要仅重新克隆已过滤的存储库,请参阅the git filter-branch documentation末尾的说明,了解如何删除这些说明。

答案 1 :(得分:1)

仍然包含子目录的旧提交仍然是存储库的一部分,即使它们无法从任何分支访问。

清理它们你可以做到

git reflog expire --expire=now --all && git gc --prune=now --aggressive

但是这会清空你的reflog。 这是必要的,因为你的reflog引用的提交不会被垃圾收集

答案 2 :(得分:0)

只是一个即用型完整版,基于@ lucanLepus接受的答案。

假设我是userA,我想从Github上的repo中完全删除历史记录media/1 Juno-Trumpet/中的文件夹(在最近的提交中不再存在,但在过去的提交中)。< / p>

注意:此特定存储库具有原始分支mastersfzwifi以及标记v1.0。为了避免需要知道这一点,我在这里使用镜像克隆(这使得一个裸存储库,这很好,因为我将使用索引过滤器)。然后,由于这是GitHub,我首先抛弃所有refs/pull/引用。

事实证明,这些文件也被命名为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

过滤分支步骤需要一段时间,并以:

结束
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/名称。由于这是一个新的克隆,没有任何reflogs到期,但我们无论如何都会这样做,然后用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个文件。)