记一次删除Git记录中的大文件的过程
app/test/target/ #查看大文件
git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')" #删除大文件或者目录
git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatch app/test/target/' --prune-empty --tag-name-filter cat -- --all #强制覆盖分支
git push origin ANT01983399_20170525_kbinfocollector --force
最近在开发一个新应用,有一天在gitlab上clone代码的时候发现我的应用竟然有170+M,明明是一个全新的应用,代码都没有几行呢,为什么会有这么大呢?
后来经过了解Git的原理,解决了这个问题,把相关内容记录下来。分享一下。
Why
我的一个新应用竟然要170+M,这是打死我我也不会信的,于是就开始分析为什么会这么大。
step 1. 把代码拉到本地
git clone git@github.com:hollischuang/Architecture-Evolution.git
只是用这个地址举例,实际并不是这个项目。
step 2. 查看哪个文件占用的空间比较大 $cd Architecture-Evolution$du -d 1 -h 174M ./.git 264K ./test 96K .
于是,发现是.git目录自己就占用了174M,了解Git的人都知道,.git目录是git自己生成的,记录了git仓库的相关信息的。看到这里其实并不难知道原因。
Git 维护着一个微型的文件系统,其中的文件也被称作数据对象。所有的数据对象均存储于项目下面的 .git/objects中。
经过我的验证,确实是.git/objects这个文件夹中的文件占了磁盘上174M的空间。
也就是说,只要我有一次将一个大文件误提交了,那么即使我后面把它删除了,但是,实际上在.git中,这个文件还是存在的,虽然我们可能再也不需要他了,但是他还在那里默默的存在着。。。
Git与大部分版本控制系统的差别是很大的,比如Subversion、CVS、Perforce、Mercurial 等等,使用的是“增量文件系统” (Delta Storage systems), 就是说它们存储每次提交(commit)之间的差异。Git正好与之相反,它会把你的每次提交的文件的全部内容(snapshot)都会记录下来。这会是在使用Git时的一个很重要的理念。
也就是说,如果我又一次把一个大文件务提交到git仓库中了,那么,下次提交时,即使你只改动了某个文件的一行内容,Git 也会生成一个全新的对象来存储新的文件内容。
因为以上两个特性,我回想起我的一次手残行为: 刚刚创建一个应用之后,我快速的写完代码,编译,运行,发现没啥问题之后,我准备先把他发布掉,于是我开始创建git仓库,并尝试把代码提交上去,这时我并没有创建.gitignore文件,我直接git add .git commit -m 'init' git push一气呵成的执行了熟悉的操作。
相信聪明的人已经发现了,逗比啊,我在编译代码之后,会有很多jar被我down到target目录下。我直接git add.把target下面的jar包,war包等这些也直接提交了。。。虽然后面我意识到,并且删除了这些文件,然后再次提交,但是由于刚我们说过的原因,这些文件依然占用着我的空间。。。
更多关于git的原理内容参见:Git 内部原理
How
问题已经定位到了,接下来就是要解决问题了。如果对git的原理及命令了解的比较多的话,这个问题还是比较好解决的,由于当时博主并不十分了解git的原理,所以做了一些知识储备之后才开始动手的。(Git 之术与道 -- 对象、为什么你的 Git 仓库变得如此臃肿)
Step 1 查看哪些历史提交过文件占用空间较大
使用以下命令可以查看占用空间最多的五个文件:
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命令用于显示已打包的内容。
step 2. 重写commit,删除大文件
使用以下命令,删除历史提交过的大文件:
git filter-branch --force --index-filter 'git rm -rf --cached --ignore-unmatch big-file.jar' --prune-empty --tag-name-filter cat -- --all
上面脚本中的big-file.jar请换成你第一步查出的大文件名,或者这里直接写一个目录。
filter-branch命令可以用来重写Git仓库中的提交
--index-filter参数用来指定一条Bash命令,然后Git会检出(checkout)所有的提交, 执行该命令,然后重新提交。
--all参数表示我们需要重写所有分支(或引用)。
在重写提交的过程中,会有以下日志输出:
Rewrite 6cdbb293d453ced07e6a07e0aa6e580e6a5538f4 (266/266)# Ref 'refs/heads/master' was rewritten
如果显示 xxxxx unchanged, 说明repo里没有找到该文件, 请检查路径和文件名是否正确,重复上面的脚本,把所有你想删除的文件都删掉。
step 3. 推送修改后的repo
以强制覆盖的方式推送你的repo, 命令如下:
git push origin master --force
step 4. 清理和回收空间
虽然上面我们已经删除了文件, 但是我们的repo里面仍然保留了这些objects, 等待垃圾回收(GC), 所以我们要用命令彻底清除它, 并收回空间,命令如下:
rm -rf .git/refs/original/git reflog expire --expire=now --allgit gc --prune=now
至此,我们已经彻底的删除了我们不想要的文件。
参考资料
Git 内部原理
Git 之术与道 -- 对象
为什么你的 Git 仓库变得如此臃肿
Git如何永久删除文件(包括历史记录)
记一次删除Git记录中的大文件的过程的更多相关文章
- 删除Git记录里的大文件
删除Git记录里的大文件 仓库自身的增长 大多数版本控制系统存储的是一组初始文件,以及每个文件随着时间的演进而逐步积累起来的差异:而 Git 则会把文件的每一个差异化版本都记录在案.这意味着,即使你只 ...
- 更好的在 Git 项目中保存大文件(Git LFS 的使用)
珠玉在前, 大家可以参考 Git LFS的使用 - 简书 为什么要用 Git LFS 原有的 Git 是文本层面的版本控制, 为代码这种小文件设计的, 保存大文件会导致 repo 非常臃肿, push ...
- 使用BFG移除git库中的大文件或污点提交
- 彻底删除 Git 项目中的文件(BFG Repo-Cleaner 用法)
一些时候由于开发初期经验不足和贪图方便, 会把一些不应该提交到 Git 的文件上传到 Github, 带来一系列安全问题, 更有可能是把一些大文件上传到 GitHub 上, 导致项目非常臃肿, 每次 ...
- 如何永久删除git仓库中敏感文件的提交记录
如何永久删除git仓库中敏感文件的提交记录 参考: 1. https://help.github.com/articles/remove-sensitive-data/
- git 彻底删除历史记录中的大文件
Reference 大家一定遇到过在使用Git时,不小心将一个很大的文件添加到库中,即使删除,记录中还是保存了这个文件.以后不管是拷贝,还是push/pull都比较麻烦. === 删除大文件方法 方法 ...
- git忽略文件并删除git仓库中的文件
问题描述 不慎在创建.gitignore 文件之前的时候将文件push到了 git仓库,即使之后在.gitignore文件中写入新的过滤规则,这些规则也不会起作用的,git依然会对所有git仓库中的 ...
- 如何删除GIT仓库中的敏感信息
如何删除GIT仓库中的敏感信息 正常Git仓库中应该尽量不包含数据库连接/AWS帐号/巨大二进制文件,否则一旦泄漏到Github,这些非常敏感信息会影响客户的信息安全已经公司的信誉.公司可能其它还有相 ...
- Git .gitignore中已添加文件路径,但仍未被忽略
当文件之前已经被提交到仓库后,后面即使将文件路径添加到 .gitignore ,使用 git status 命令,依然会看到文件被修改. $ git status 位于分支 master 您的分支与上 ...
随机推荐
- JAVA学习路线图---(JAVA1234) 分类: B1_JAVA 2013-10-05 10:22 502人阅读 评论(1) 收藏
转自:http://blog.csdn.net/pplcheer/article/details/12276999 第一阶段-Java基础 这一阶段很重要,关系到你后面阶段的学习,所以务 ...
- 11G、12C安装结束需要做的一些操作
修改spfile参数:修改前,先备份 create pfile from spfile; alter system set memory_target=0 scope=spfile;alter sys ...
- Visual Stdio 环境下使用 GSL (GNU Scientific Library)
Visual Stdio 环境下使用 GSL (GNU Scientific Library) 经測试.这里的方法不适用于VS2015. * 这篇文章有点过时了.建议从以下网址下载能够在 vs 环境下 ...
- pthread_join/pthread_exit的使用方法解析
官方说法: 函数pthread_join用来等待一个线程的结束.函数原型为: extern int pthread_join __P ((pthread_t __th, void **__thread ...
- poj 2965 The Pilots Brothers' refrigerator
The Pilots Brothers' refrigerator Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 18040 ...
- iOS 9和xcode7设置
升级了Xcode7各种问题来了,折腾两天 一.Xcode7 http适配设置 1.大部分社交平台接口不支持https协议. 2.大部分社交平台SDK不支持bitcode. 3.添加Scheme白名单 ...
- IT咨询服务-客户案例(四):根据图片等素材,动态生成个性化图片
最近,慕名而来一个客户. 客户的目标 网站来一个用户,选择模版,上传图片等素材,生成自定义的图片,或者静态网站,然后分享到社交网站.有点类似于,网上制作名片,选择模版,输入个人信息,生成名片的设 ...
- oracle中imp导入数据中文乱码问题(转)
(转自 http://blog.chinaunix.net/uid-186064-id-2823338.html) oracle中imp导入数据中文乱码问题 用imp命令向oracle中导入数据后, ...
- HDU 5293 Train chain Problem - 树链剖分(树状数组) + 线段树+ 树型dp
传送门 题目大意: 一颗n个点的树,给出m条链,第i条链的权值是\(w_i\),可以选择若干条不相交的链,求最大权值和. 题目分析: 树型dp: dp[u][0]表示不经过u节点,其子树的最优值,dp ...
- Windows安装Jekyll
Run Jekyll on Windows 夹 Jekyll介绍 安装Ruby 安装DevKit 安装Jekyll 安装Python 安装pip 执行Jekyll Introduction Jekyl ...