如何从我的git仓库中删除未引用的blob

时间:2009-12-15 02:28:06

标签: git

我有一个GitHub回购,有两个分支 - master&释放。

发布分支包含二进制分发文件,这些文件导致了非常大的repo大小(> 250MB),所以我决定清理它们。

首先,我通过git push origin :release

删除了远程发布分支

然后我删除了本地发布分支。首先我尝试git branch -d release,但是git说“错误:分支'释放'不是你当前HEAD的祖先。”这是真的,所以我做了git branch -D release强迫它被删除。

但我的本地和GitHub上的存储库大小仍然很大。所以,我运行了通常的git命令列表,比如git gc --prune=today --aggressive,没有运气。

SO 1029969跟随Charles Bailey的指示,我得到了最大blob的SHA1列表。然后我使用SO 460331中的脚本来查找blob ...并且最大的五个不存在,虽然找到了较小的blob,所以我知道脚本正在运行。

我认为这些博客是发布分支中的二进制文件,并且在删除该分支后它们会以某种方式遗留下来。什么是摆脱它们的正确方法?

10 个答案:

答案 0 :(得分:170)

...而且没有进一步的麻烦,我可以向您呈现这个有用的命令,“git-gc-all”,保证删除所有你的git垃圾,直到它们可能出现额外的配置变量:

git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc

你可能还需要先运行类似的东西哦,亲爱的,git很复杂!!

git remote rm origin
rm -rf .git/refs/original/ .git/refs/remotes/ .git/*_HEAD .git/logs/
git for-each-ref --format="%(refname)" refs/original/ | xargs -n1 --no-run-if-empty git update-ref -d

你可能还需要删除一些标签,谢谢Zitrax:

git tag | xargs git tag -d

我把所有这些都放在一个脚本中:git-gc-all-ferocious

答案 1 :(得分:59)

如上所述here,只需使用

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

git reflog expire --expire-unreachable=now --all删除reflog中无法访问的所有提交。

git gc --prune=now自行删除提交。

注意:仅使用git gc --prune=now将无效,因为这些提交仍在reflog中引用。因此,清除reflog是必需的。

答案 2 :(得分:32)

this SO answer中所述,git gc实际上可以增加回购的大小!

另见this thread

  

现在git有一个安全机制,可以在运行“git gc”时立即删除未引用的对象。
  默认情况下,未引用的对象会保留2周。这是为了让您轻松恢复意外删除的分支或提交,或者避免竞争可能会被正在运行的“git gc”进程删除正在创建但尚未引用的对象的竞争并行。

     

因此,为了将宽限期赋予已包装但未引用的对象,重新包装过程将那些未被引用的对象推出其松散的形状,以便它们可以老化并最终被修剪。
  对象变得未被引用通常不是那么多。拥有404855未引用的对象是非常多的,并且通过克隆首先发送这些对象是愚蠢的,完全浪费网络带宽。

     

无论如何......要解决您的问题,您只需要使用git gc参数运行'--prune=now'来禁用该宽限期并立即删除那些未引用的对象(仅当没有其他git活动同时发生,应该很容易在工作站上确保。

     

顺便说一下,使用“git gc --aggressive”和更高版本的git(或“git repack -a -f -d --window=250 --depth=250”)

same thread mentions

 git config pack.deltaCacheSize 1
  

将delta缓存大小限制为一个字节(有效禁用它),而不是默认值0,这意味着无限制。有了这个,我可以在x86-64系统上使用上面的git repack命令重新打包该存储库,该系统具有4GB的RAM并使用4个线程(这是一个四核)。尽管如此,驻留内存使用量增长到接近3.3GB。

     

如果您的计算机是SMP且没有足够的RAM,那么您可以将线程数减少到只有一个:

git config pack.threads 1
  

此外,您可以使用--window-memory argument至“git repack”进一步限制内存使用量   例如,使用--window-memory=128M应该在delta上保持合理的上限   搜索内存使用情况虽然这可能会导致回购时的最佳delta匹配   包含许多大文件。


在过滤器分支方面,您可以考虑(谨慎)this script

#!/bin/bash
set -o errexit

# Author: David Underhill
# Script to permanently delete files/folders from your git repository.  To use 
# it, cd to your repository's root and then run the script with a list of paths
# you want to delete, e.g., git-delete-history path1 path2

if [ $# -eq 0 ]; then
    exit 0
fi

# make sure we're at the root of git repo
if [ ! -d .git ]; then
    echo "Error: must run this script from the root of a git repository"
    exit 1
fi

# remove all paths passed as arguments from the history of the repo
files=$@
git filter-branch --index-filter "git rm -rf --cached --ignore-unmatch $files" HEAD

# remove the temporary history git-filter-branch otherwise leaves behind for a long time
rm -rf .git/refs/original/ && git reflog expire --all &&  git gc --aggressive --prune

答案 3 :(得分:18)

git gc --prune=now或低级git prune --expire now

答案 4 :(得分:12)

每当你的HEAD移动时,git会在reflog中跟踪它。如果你删除了提交,你仍然有“悬空提交”,因为它们仍被reflog引用了大约30天。当您意外删除提交时,这是安全网。

您可以使用git reflog命令删除特定提交,重新包装等,或者仅使用高级命令:

git gc --prune=now

答案 5 :(得分:4)

您可以使用git forget-blob

使用非常简单git forget-blob file-to-forget。你可以在这里获得更多信息

https://ownyourbits.com/2017/01/18/completely-remove-a-file-from-a-git-repository-with-git-forget-blob/

它将从您的历史记录,reflog,标签等中的所有提交中消失

我时不时遇到同样的问题,每次我都要回到这篇文章和其他人那里,这就是为什么我要自动化这个过程。

Sam Watkins等贡献者的信用

答案 6 :(得分:2)

尝试使用git-filter-branch - 它不会删除大blob,但它可以删除您从整个repo指定的大文件。对我来说,它将repo大小从几百MB减少到12 MB。

答案 7 :(得分:1)

在执行git filter-branchgit gc之前,您应该查看回购协议中存在的标记。任何对持续集成和部署等事件进行自动标记的真实系统都会使这些标记仍然引用不需要的对象,因此gc无法删除它们,您仍然会想知道为什么repo的大小仍然很大

摆脱所有不需要的东西的最佳方法是运行git-filter& git gc然后将主人推送到一个新的裸仓库。新的裸仓库将有清理后的树。

答案 8 :(得分:0)

有时,“gc”没有做太多好处的原因是基于旧提交存在未完成的rebase或stash。

答案 9 :(得分:0)

要添加其他提示,请不要忘记使用 git remote prune 删除遥控器的过时分支,然后再使用 git gc

你可以用 git branch -a

看到它们

从github和forked存储库中获取时,它通常很有用......