太坑了。。。Git仓库为什么越来越大

122 阅读7分钟

背景

上个月开源了一套低代码平台 marsview ,陆陆续续有一些对低代码感兴趣的兄弟加入,开启了贡献之路,有不少功能都是小伙伴提交的。

然后最近发生一件事儿,小伙伴发现开源仓库越来越大,克隆的时候已经有 200 多 M 了,可是下载仓库包发现只有 4.7M ,这是为什么?

其实,我第一反应就是,.git 记录了历史缓存,但我没想到的是,克隆包居然高达200多M,不能容忍....

问题跟踪

marsview 当前仓库源码其实只有4.7M,究竟是什么原因导致变成了250M,我们也就迭代了一个月左右。

于是,我开始翻找历史提交记录,果不其然,我们在开源后的一周,上线了开发文档,当时,我跟小伙伴录制了几个视频,一开始为了节省 CDN 流量,我把视频文件放到了文档仓库提交到远程了,后来感觉不合理,又选择上传到了百度云,但是视频文件最终是被删除的,没想到变成了历史文件,虽然当前视频文件已经被删除了,但是 git 的历史包里面却被打包进去了。

当前开源项目下载包大小

image.png

历史提交的视频文件记录

image.png

打开项目.git目录查看历史打包文件大小

image.png

所以,我们已经找到根本原因了,只要你历史提交过大文件,那你的代码仓库就会有记录,即使你最后又删除了大文件也没用。

这样带来的影响是什么 ?

最大的影响就是别人克隆你的仓库非常慢,一看250M,直接走了。

解决思路

说实话,这个问题解决起来很棘手,我尝试在网上寻找答案:有说,git reset ,有说,git revert ,也有人说 git rebase

其实仔细想一想,前两个都不太可能,我们是要抹除历史记录,相当于要把曾经提交视频的那一次给它干掉,我尝试了使用git rebase,因为它可以把历史记录进行合并、修改或删除。

使用 git rebase

1. 找到添加视频的那一次提交

image.png

2. 复制版本号,执行rebase

git rebase -i a256f5058c3478ea12244db0a6ccb980825d98bd^

我们加一个^,往前执行一步

image.png

很快就发现了这两次提交记录,我们输入i进入输入模式,把那两次提交前面的pick改成drop,这样最终的提交记录里面就找不到这两次视频的提交。

这个过程中,如果有冲突,就解决一下冲突,直接提交commit,然后继续执行:git rebase --continue,直到把所有冲突解决完,然后强推上去。

3. 强推一下,查看效果

通过git rebase以后,我查看了github提交记录,确实已经找不到这两个视频的提交了,然而我去重新克隆仓库,发现依然是250M,见鬼了,说明通过git reset/revert/rebase这种操作只是处理提交日志,解决不了历史缓存问题。

【这里我当时忘了截图了,查看GitHub已经找不到视频的提交记录了】

git filter-branch

网上介绍说,需要通过git filter-branch来解决历史缓存问题,于是我就照搬了。 幸亏我在执行git rebase之前,把仓库备份了,要不然还挺麻烦。

1. 执行命令

git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch packages/docs/src/pbulic/project.mp4' --tag-name-filter cat -- --all

git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch packages/docs/src/pbulic/editor.mp4' --tag-name-filter cat -- --all

参数解释:

  • filter-branch 是让git重写每一个分支。

  • --force 假如遇到冲突也让git强制执行。

  • --index-filter 选项指定重写的时候应该执行什么命令,要执行的命令紧跟在它的后面,在这里就是git rm --cached --ignore-unmatch password.txt ,让git删除掉缓存的文件,如果有匹配的话。

  • --prune-empty 选项告诉git,如果因为重写导致某些commit变成了空(比如修改的文件全部被删除),那么忽略掉这个commit。

  • --tag-name-filter 表示对每一个tag如何重命名,重命名的命令紧跟在后面,当前的tag名会从标注输入送给后面的命令,用cat就表示保持tag名不变。

  • -- 表示分割符。

执行的时候,它会生成一个重写的.git-rewrite目录,看起来有效果,当时全部执行完以后,发现objects目录大小并没有变化,但objects下面多了很多子目录,看起来是每一次提交的历史日志,然而.pack文件大小始终没有变化。

image.png

image.png

我们最重要的就是要把这个pack文件降下去,否则就是徒劳。

2. 通过gc回收

第一步查找记录,删除日志文件,第二步就是清理,因为历史记录都是打包在.pack文件里面的。

设置过期

git reflog expire --expire=now --all

打包、回收

git gc --aggressive --prune=now

image.png

果然.pack文件变小了,说明前面几步执行是成功的,因为我们视频没有删除完,所有当前还有32M

强推、查看提交记录

  • 继续执行上面的命令,删除所有视频文件。
  • 强制推送代码到远程:git push origin main --force
  • 查看github远程记录

image.png

查看GitHub历史,分析只有代码,没有视频文件了。

总结

随着版本的迭代,仓库大小会越来越大,对于大文件的提交(视频、jar、SDK..)一定要慎重考虑是否提交到仓库,避免不必要的困扰。

如果不小心发生了,跟我一样的情况,就按这个思路解决:

  1. 执行git filter-branch
git filter-branch --force --prune-empty --index-filter 'git rm -rf --cached --ignore-unmatch packages/docs/src/pbulic/editor.mp4' --tag-name-filter cat -- --all
  1. 执行git reflog
git reflog expire --expire=now --all
  1. 执行git gc
git gc --aggressive --prune=now

号外

最近低代码强力更新,欢迎大家体验

image.png

image.png

image.png

体验地址: www.marsview.cc/