如何从我的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
。 你可以在这里获得更多的信息
它会从你的历史中的所有提交中消失,reflog,标签等等
我偶尔遇到同样的问题,每次我都要回到这个post和其他人,这就是为什么我会自动化这个过程。
向Sam Watkins等贡献者致谢
尝试使用git-filter-branch – 它不会删除大的斑点,但可以删除您从整个回购指定的大文件。 对我来说,它将回购大小从几百MB降低到12 MB。
要添加另一个技巧,不要忘记在使用git gc之前,使用git remote prune来删除远端的过时分支
你可以看到他们与GIT分支-a
从github和分叉存储库中获取时通常很有用…
在做git filter-branch
和git gc
,你应该检查存在于你的仓库中的标签。 任何具有自动标记function的实际系统,如持续集成和部署,都会使不需要的对象仍然被这些标记引用,因此gc
无法删除它们,您仍然会不断想知道为什么repo的大小仍然如此之大。
摆脱所有不想要的东西的最好方法是运行git-filter
& git gc
,然后将master推到一个新的裸回购。 新的裸回购将有清理树。
有时候,“gc”没有太多好处的原因是,有一个未完成的rebase或基于旧的提交存储。