git: 如何减少.git文件的大小?

1 起因

使用git储存本地笔记时,没有注意到其中包含的视频文件(.avi 大约3个,每个100MB),将其也添加到git的历史记录中(git add . && git commit),虽然之后删除了视频文件本身,但其提交记录永久的留在了 .git中,被git保存为了Blob对象储存起来了,导致 .git目录 400MB+,无法进行push到github,也没有必要,于是开始瘦身之旅。

2 git gc 修剪历史提交

大体来说,当运行 “git gc” 命令时,Git会收集所有松散对象并将它们存入 packfile,合并这些 packfile 进一个大的 packfile,然后将不被任何 commit 引用并且已存在一段时间 (数月) 的对象删除。 此外,Git还会将所有引用 (references) 并入一个单独文件。

命令[1]:git gc --prune=now

就细节而言,Git做了这几件事:

pack_refs 过程
reflog expire 过程
repack 过程
prune 过程
rerere 过程
pack_refs 过程相当于执行"git pack-refs --all --prune",它会将$GIT_DIR/refs目录下的所有heads和tags打包成一个文件并保存为\$GIT_DIR/packed-refs下。

reflog expire 过程相当于执行"git reflog expire --all",它会将删除所有超过期限而且没有被refs涉及的reflog条目。

repack 过程相当于执行"git repack -d -l",一般情况下还会包括"-A"选项,它会将所有未被包含在一个pack的松散对象连结成一个pack,也会将现有的pack重新组织为一个新的更有效率的pack,并删除冗余的pack(如果她们中存在不可达的松散对象,会先把这些对象释放出来)。

prune 过程相当于执行"git prune --expire",他会删除所有过期的、不可达的且未被打包的松散对象。

rerere 过程相当于执行"git rerere gc",这种情形下似乎没什么用。

参考:https://blog.csdn.net/lihuanshuai/article/details/37345565

3 删除.git中的大文件

Step 1. 查看哪些历史提交过文件占用空间较大

使用以下命令可以查看占用空间最多的五个文件:
命令[2]:git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

可以获得类似于以下的结果:
git: 如何减少.git文件的大小?_第1张图片
其中前面为文件的id(hah值),目前不用管,我们需要的是后面的所有内容,为文件的目录+名字。
如这里的名字便是:dadi 12 NodeJs 封装静态WEB服务、 路由、EJS模板引擎、GET、POST(上) (17分23秒)/12 NodeJs 封装静态WEB服务、 路由、EJS模板引擎、GET、POST(上) (17分23秒)/NodeJs 封装静态WEB服务、 路由、EJS模板引擎、GET、POST.avi
(后悔使用这么长的文件名)
如果你的文件名较短或者文件目录比较浅,可能级只是data/xxx.mp4这样的格式。

拓展:
rev-list命令用来列出Git仓库中的提交,我们用它来列出所有提交中涉及的文件名及其ID。 该命令可以指定只显示某个引用(或分支)的上下游的提交。
–objects:列出该提交涉及的所有文件ID。
–all:所有分支的提交,相当于指定了位于/refs下的所有引用。
verify-pack命令用于显示已打包的内容。

这里本来应该是两步:1.找出id;2根据id找出文件名
两步的方法:
git: 如何减少.git文件的大小?_第2张图片
更多资料请访问文末参考中的[2]知乎回答

Step 2. 重写commit,删除大文件

命令[3]:git filter-branch --force --index-filter "git rm --cached --ignore-unmatch 'yourFileName'" --prune-empty --tag-name-filter cat -- --all
这里需要把命令中的 yourFileName改成上一步获取到的文件名称。
例如:git filter-branch --force --index-filter "git rm --cached --ignore-unmatch 'dadi 11 nodejs创建一个静态WEB服务器 读取文件获取响应类型 处理异步(下)/11 nodejs创建一个静态WEB服务器 读取文件获取响应类型 处理异步(下)/nodejs创建一个静态WEB服务器 读取文件获取响应类型 处理异步.avi'" --prune-empty --tag-name-filter cat -- --all

结果示例:
git: 如何减少.git文件的大小?_第3张图片
成功会显示 Rewrite xxxx(233/666).
如果显示 xxxxx unchanged, 说明repo里没有找到该文件, 请检查路径和文件名是否正确。

重复上面的脚本,把所有你想删除的文件都删掉。

step 3. 进行repack

命令[4]:

$ git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
$ git reflog expire --expire=now --all
$ git gc --prune=now

作者:郑宇
链接:https://www.zhihu.com/question/29769130/answer/315745139
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

step 4. 查看 pack 的空间使用情况

命令[5]:git count-objects -v

step 5. 推送修改后的repo

以强制覆盖的方式推送你的repo, 命令如下:
命令[6]:git push origin master --force

step 6. 清理和回收空间

虽然上面我们已经删除了文件, 但是我们的repo里面仍然保留了这些objects, 等待垃圾回收(GC), 所以我们要用命令彻底清除它, 并收回空间,命令如下:
命令[7]:

rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now

4 END 和 注意事项

至此你会发现.git的大小已经变为正常大小,瘦身完成。
注意:以上内容参考了文末参考文章,经过整合可能会有重复的步骤,比如gc了两次,不过多做无害,如果有更为精简的实验方法欢迎讨论。
注意2:以上内容最好都在 git bash中运行,不要再vs code 的命令行(即windows的cmd),否则会不能识别命令。

在这里插入图片描述
Input file specified two times.

‘tail’ is not recognized as an internal or external command,
operable program or batch file.

‘grep’ is not recognized as an internal or external command,
operable program or batch file.

参考

  1. 记一次删除Git记录中的大文件的过程
  2. 如何解决 GitHub 提交次数过多 .git 文件过大的问题? - 郑宇的回答 - 知乎

你可能感兴趣的:(git,git,.git,整理,大文件,.git太大)