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

kkr*_*ler 113 git

我有一个GitHub仓库,有两个分支 - 主和发布.

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

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

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

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

按照Charles Bailey在SO 1029969的指示,我得到了最大blob的SHA1列表.然后我使用来自SO 460331的脚本 来找到blob ......并且五个最大的不存在,虽然找到了较小的blob,所以我知道脚本正在工作.

我认为这些博客是发布分支中的二进制文件,它们在删除该分支后不知何故.什么是摆脱它们的正确方法?

Sam*_*ins 192

...而且没有进一步的麻烦,我可以向您呈现这个有用的命令,"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
Run Code Online (Sandbox Code Playgroud)

你可能还需要先运行这样的东西哦,亲爱的,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
Run Code Online (Sandbox Code Playgroud)

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

git tag | xargs git tag -d
Run Code Online (Sandbox Code Playgroud)

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

  • 这值得投票.它终于摆脱了很多其他方法所保留的git对象.谢谢! (9认同)
  • @Redsandro,据我所知,那些“git rm origin”、“rm”和“git update-ref -d”命令删除了对遥控器等旧提交的引用,这可能会阻止垃圾收集。"git gc" 的选项告诉它不要保留各种旧提交,否则它会保留一段时间。例如 gc.rerereresolved 用于“您之前解决的冲突合并记录”,默认保留 60 天。这些选项位于 git-gc 联机帮助页中。我不是 git 专家,也不确切知道所有这些东西的作用。我从联机帮助页中找到了它们,并且 grepping .git 用于提交引用。 (2认同)
  • 所以这个方法对我不起作用。我发现引用仍然存在于 `.git/info/refs` 和 `.git/packed-refs` 中。用 vim 删除这些引用,然后运行命令成功。虽然我不完全确定邪恶的提交不在一个包里。所以我将这些包解压为 http://stackoverflow.com/questions/16972031/how-to-unpack-all-objects-of-a-git-repository 以获得良好的测量。我可能会建议人们只做一个克隆,然后吹走原始存储库。 (2认同)

Eli*_*iko 68

如上所述这里,只需使用

git reflog expire --expire-unreachable=now --all
git gc --prune=now
Run Code Online (Sandbox Code Playgroud)

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

git gc --prune=now 删除提交本身.

注意:只有使用git gc --prune=now才会起作用,因为这些提交仍在reflog中引用.因此,清除reflog是必需的.

  • 它有效,但不知怎的,我在这个过程中丢失了我保存的藏匿处(在我的情况下没有什么重要的,只是对其他人的警告) (8认同)
  • 我认为这个答案需要一个明确的警告,最好是在顶部。我的编辑建议被拒绝了,因为我想我应该在评论中向作者建议?请接受此编辑 https://stackoverflow.com/review/suggested-edits/26023988 或以您自己的方式添加警告。另外,这**会掉落你所有的藏品**。警告中也应该提及这一点! (5认同)
  • `git fetch --prune` 由于删除本地 blob 进一步减小了大小。 (2认同)

Von*_*onC 33

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

见此主题

现在,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')

同一个线程中提到:

 git config pack.deltaCacheSize 1
Run Code Online (Sandbox Code Playgroud)

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

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

git config pack.threads 1
Run Code Online (Sandbox Code Playgroud)

此外,您可以使用--window-memory argumentto' git repack' 进一步限制内存使用量.
例如,使用--window-memory=128M应该在delta搜索内存使用上保持合理的上限,尽管如果repo包含大量大文件,这可能导致不太理想的delta匹配.


在filter-branch前面,你可以考虑(谨慎)这个脚本

#!/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
Run Code Online (Sandbox Code Playgroud)


Jak*_*ski 19

git gc --prune=now或低水平git prune --expire now.


vdb*_*oor 12

每次HEAD移动时,git都会跟踪它reflog.如果你删除了提交,你仍然有"悬挂提交",因为它们仍被引用reflog~30天.当您意外删除提交时,这是安全网.

您可以使用git reflog命令remove specific commits,repack等,或者只使用高级命令:

git gc --prune=now
Run Code Online (Sandbox Code Playgroud)


W55*_*4xv 1

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

  • 现在 _that_ 是一个可怕的命令:)当我的 git-fu 感觉更强大时,我必须尝试一下。 (6认同)