如何从我的git回购中删除未引用的blob

我有一个GitHub回购有两个分支 – 主和释放。

发行版分支包含二进制分发文件,这些文件有助于产生非常大的回购大小(> 250MB),所以我决定清理干净。

首先,我通过git push origin :release删除了远程发布分支

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

但是,我的存储库大小,无论是在本地和GitHub,仍然巨大。 然后我跑过通常的git命令列表,比如git gc --prune=today --aggressive ,没有运气。

按照Charles Bailey在SO 1029969的指示,我能够获得最大斑点的SHA1列表。 然后,我用SO 460331的脚本来查找blob …,而最大的五个不存在,尽pipefind了更小的blob,所以我知道脚本正在工作。

我认为这些博客是发布分支的二进制文件,在删除那个分支之后,他们不知怎的就离开了。 什么是正确的方式摆脱他们?

…不用多说,我可以向你展示这个有用的脚本, git-gc-all ,保证删除所有的git垃圾,直到他们可能出现额外的configurationvariables:

 git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 \ -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@" 

– 冲突选项可能会有所帮助。

你可能也需要先运行这样的东西,哦,亲爱的,混帐是复杂的!

 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 

我把这一切放在脚本里,在这里:

http://sam.nipl.net/b/git-gc-all-ferocious

编辑:您可能还需要删除一些标签,谢谢Zitrax:

 git tag | xargs git tag -d 

如此处所述,只需使用

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

git reflog expire --expire-unreachable=now --all删除reflog中所有不可达提交的reflog

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

注意 :只有使用git gc --prune=now才能工作,因为这些提交仍然在reflog中被引用。 因此,清除reflog是强制性的。

正如在这个回答中提到的, git gc实际上可以增加回购的大小!

另见这个线程

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

因此,为了将这个宽限期交给包装但是未被引用的对象,重新包装过程将那些未被引用的对象从包装中拉出来,变成松散的forms,以便它们能够被老化并最终被修剪。
变成未被引用的对象通常不是那么多。 有404855个未被引用的对象是相当多的,而通过一个克隆发送这些对象首先是愚蠢的,并且完全浪费了networking带宽。

无论如何…要解决你的问题,你只需要运行带有--prune=now参数的' git gc '来禁用这个宽限期,并立即摆脱这些未被引用的对象(只有在没有其他git活动正在在工作站上应该容易确保的同时放置)。

和顺便说一句,使用' git gc --aggressive '后面的git版本(或' git repack -a -f -d --window=250 --depth=250 ')

同一个线程提到 :

  git config pack.deltaCacheSize 1 

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

如果你的机器是SMP,并且你没有足够的RAM,那么你可以把线程的数量减less到只有一个:

 git config pack.threads 1 

另外,你可以通过--window-memory argument来进一步限制内存的使用,以“ git repack ”。
例如,使用--window-memory=128M应该在deltasearch内存使用上保持一个合理的上限,尽pipe如果repo包含许多大文件,这可能导致较less的最佳delta匹配。


在filter分支前面,您可以考虑(谨慎) 这个脚本

 #!/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, eg, 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 

git gc --prune=now ,或者低级的git prune --expire now

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

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

 git gc --prune=now 

你可以使用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,标签等等

我偶尔遇到同样的问题,每次我都要回到这个post和其他人,这就是为什么我会自动化这个过程。

向Sam Watkins等贡献者致谢

尝试使用git-filter-branch – 它不会删除大的斑点,但可以删除您从整个回购指定的大文件。 对我来说,它将回购大小从几百MB降低到12 MB。

要添加另一个技巧,不要忘记在使用git gc之前,使用git remote prune来删除远端的过时分支

你可以看到他们与GIT分支-a

从github和分叉存储库中获取时通常很有用…

在做git filter-branchgit gc ,你应该检查存在于你的仓库中的标签。 任何具有自动标记function的实际系统,如持续集成和部署,都会使不需要的对象仍然被这些标记引用,因此gc无法删除它们,您仍然会不断想知道为什么repo的大小仍然如此之大。

摆脱所有不想要的东西的最好方法是运行git-filtergit gc ,然后将master推到一个新的裸回购。 新的裸回购将有清理树。

有时候,“gc”没有太多好处的原因是,有一个未完成的rebase或基于旧的提交存储。