目录

记录删除.git记录大文件的过程

在公司项目中遇到 .git 文件夹有800m+,才拉取项目时把我惊呆了,什么玩意?

在了解Git原理之后解决了这个问题

Why

很多人更新代码都是通过git add . (不知道哪里学来的) 这样做有什么问题呢, 假如项目中有.sql .zip文件他都会打包进去,这样做会导致什么后果的,其实你们应该猜到了,.git也是吧你提交的记录缓存到本地文件的,普通情况缓存代码是很正常的,但是如果你把一些奇奇怪怪的文件放进来了, 就会导致git记录特别大,假以时日.git文件夹超过1G都是正常的,那么应该这么办呢?

step 1 查看那个文件占用空间

$ du -d 1 -h
840M   ./.git

Git 维护着一个微型的文件系统,其中的文件也被称作数据对象。所有的数据对象均存储于项目下面的 .git/objects中。 Git与大部分版本控制系统的差别是很大的,比如Subversion、CVS、Perforce、Mercurial 等等,使用的是“增量文件系统” (Delta Storage systems), 就是说它们存储每次提交(commit)之间的差异。Git正好与之相反,它会把你的每次提交的文件的全部内容(snapshot)都会记录下来。这会是在使用Git时的一个很重要的理念。

也就是说,如果我又一次把一个大文件务提交到git仓库中了,那么,下次提交时,即使你只改动了某个文件的一行内容,Git 也会生成一个全新的对象来存储新的文件内容。

How

解决问题

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

通过 git rev-list --objects 命令能够查看缓存在git的文件

$ git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

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

2. 重写 commit , 删除大文件

注意 xxx.zip为上一步查询出来的文件根据需要可以选择删除某些文件

使用 git-filter-branch太慢了 1w commit 平均40分钟左右

使用git-filter-repo 秒级神器 https://github.com/newren/git-filter-repo

安装方法推荐使用 pip install git-filter-repo
$ git filter-repo --invert-paths --path "xxx.zip"

几秒钟的时间就跑完比之前 filter-branch 快了不是一个量级

老版 $ git filter-branch –force –index-filter ‘git rm -rf –cached –ignore-unmatch xxx.zip’ –prune-empty –tag-name-filter cat – –all filter-branch命令可以用来重写Git仓库中的提交 –index-filter参数用来指定一条Bash命令,然后Git会检出(checkout)所有的提交, 执行该命令,然后重新提交。 –all参数表示我们需要重写所有分支(或引用)。

在重写提交的过程中,会有以下日志输出:

Rewrite 6cdbb293d453ced07e6a07e0aa6e580e6a5538f4 (266/266)
# Ref 'refs/heads/master' was rewritten

如果显示 xxxxx unchanged, 说明repo里没有找到该文件, 请检查路径和文件名是否正确,重复上面的脚本,把所有你想删除的文件都删掉。

3. 清理和回收空间

虽然上面我们已经删除了文件, 但是我们的repo里面仍然保留了这些objects, 等待垃圾回收(GC), 所以我们要用命令彻底清除它, 并收回空间,命令如下: 注意: 默认代码管理平台都不会自动GC, 你本地清理推送之后可能会需要到平台进行GC,具体步骤自行百度

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

4. 强制推送 repo

当你认为已经删除完需要删除的文件后, 以强制覆盖的方式推送你的repo, 命令如下:

$ git push origin master --force

至此,我们已经彻底的删除了我们不想要的文件。

结尾

最后查看一下文件删除后的大小

$ du -d 1 -h
10M   ./.git