坑的由来

repo中不小心上传了许多测试生成的data。结果可想而知,原本只有代码的仓库突然间变得无比臃肿(或者是慢慢臃肿),从早期的几十MB,迅速飙升至1G.

到底发生了什么

早些时候我对git的原理并不是很了解,只是随着日常使用,终于开始理解git其实是一个指针指向一次提交的对象,当你在各个分支间切换的时候,指针就随之切换,版本也随之更改。

那么,git 是如何做到的能在各个版本间无缝切换的呢。即使long long ago的代码,只要来一句git reset --hard sesd54f54sdf5sd4sd5f 照样给你打回原形。

在相应的git文件夹里面 按下面组合键 可以看到隐藏的.git版本控制文件

ctrl+h

真相只有一个,那就是其实所有的版本,不管是否存在了多久,都仍然存在于硬盘里。所以你才可以任性地对代码为所欲为。然而,为所欲为也要付出代价。

代价就是,你删了几次,就会有几个快照存在于硬盘里。删一个大视频,表面上少了500M空间,实则增加了一次至少500M的历史提交记录,虽然现在的代码仓库里不再有这个视频,但是你试试du -sh .git看看.git 文件大小,是不是有惊喜?我在这儿体会的最恐怖的一次,见证了3个多G的.git

如何 解决

首先我们看看git相关文件占用的空间,运行

git count-objects -v

size-pack以千字节为单位表示,那么这里就有0.3G大小,这对代码仓库来说可是个恐怖的数字了。

那么让我们来找出罪魁祸首——到底是哪些大文件在混淆视听。

将所有含这些大文件的历史提交记录,一个不漏的找出来。

tail -30 表示 列举前30项

git rev-list --objects --all | grep -E `git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -30 | awk '{print$1}' | sed ':a;N;$!ba;s/\n/|/g'`

然后移除对该文件的引用 也就是 (tests_run_one.....后面一长串)  (使用filter-branch去除大文件)

git filter-branch --force --index-filter "git rm --cached --ignore-unmatch 'tests_run_one.....后面一长串'"  --prune-empty --tag-name-filter cat -- --all

进行repack

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin

# 指示Git清除不需要的数据:
git reflog expire --expire=now --all && git gc --prune=now --aggressive

查看pack的空间使用情况

git count-objects -v

查看.git的实际大小

du -sh .git

强制把本地的分支(这里是master)更改推送到git服务器分支

git push origin  --force --all

参数 origin 是远程仓库地址别名, 具体请参照 git remote -v 命令 查看选择
参数 --force 是强制推送, 这个参数表示强行覆盖远程仓库, 这个参数跟TNT一样危险不能乱用, 它可以简写为 -f
参数 --all 表示所有历史都要覆写, 当然我不知道这里的 “全部” 是多少, 教程里还提到了再提交一次 tags 的

强制push tags

git push origin  --force --tags

需要把这一次的改动提交到远端仓库:

git push --force --verbose --dry-run
git push --force

依次执行以下命令

rm -rf .git/refs/original/

git reflog expire --expire=now --all

git fsck --full --unreachable

git repack -A -d

git gc --aggressive --prune=now

git push --force

注:这一步可能会收到错误,原因是protected的分支不能进行覆盖推送,可以首先把当前分支修改为unprotected,在仓库的设置中可以修改。

到此,大文件已经从仓库中清除了,重新拉一个仓库,速度变快了,可以看到仓库的体积已经变小了,注意:一定要重新拉取仓库。

最后告诉你的同事使用pull rebase而不是使用merge来更新他们分支。如果使用merge,他们本地的.git可能会覆盖你之前做的清理工作,再次push 的时候会让本地仓库再次引入到远程库中

或者告知他们下次 重新git clone

 事实上有两种处理方法 参考gitlab官方文档 Reducing the repository size using Git

https://docs.gitlab.com/ee/user/project/repository/reducing_the_repo_size_using_git.html#reducing-the-repository-size-using-git

 如果要使用BFG清除git仓库中的隐私文件或大文件参考下面

https://www.cnblogs.com/huipengly/p/8424096.html

当repo只有默认的master的时候 以上是可以完成需求的

 

实验证明 如果repo 有其他分支(除了master分支之外) 以上指令没有效果 也就是远程端 并没有减少库容量 因为分支没有得到push 实际上--all参数是失效的

首先创建本地

查看远程分支名称

git branch -r

远程先开好分支然后拉到本地( 本地分支会和远程分支建立一定关联)

git checkout -b Tests origin/Tests //检出远程的Tests分支到本地Tests

查看本地分支 是否切换到刚创建的

git branch

 git gc

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

强制 PUSH远程分支

git push origin Tests:Tests --force //推送本地的Tests(冒号前面的)分支到远程origin的Tests(冒号后面的)分支(没有会自动创建)

本文参考

https://blog.csdn.net/qq_40233736/article/details/86668768

https://kyriejoshua.github.io/jo.github.io/2016/07/17/how-to-clear-huge-files-in-git/

https://www.jianshu.com/p/17e5adf47da5

在git多分支repo仓库中彻底清除大文件的更多相关文章

  1. git 仓库中删除历史大文件

    git 仓库中删除历史大文件 在git中增加了一个很大的文件,而且被保存在历史提交记录中,每次拉取代码都很大,速度很慢.而且用删除 提交历史记录的方式不是很实际. 以下分几个步骤介绍如何减小.git文 ...

  2. 由于github仓库中提前建立readme文件,导致git push报错error: failed to push some refs to 'git@github.com:

    $ git push -u origin master To git@github.com:xxx/xxx.git ! [rejected] master -> master (fetch fi ...

  3. Linux系统中如何查找大文件或文件夹的方法

    在Windows系统中,我们可以使用TreeSize工具查找一些大文件或文件夹,非常的方便高效,在Linux系统中,如何去搜索一些比较大的文件呢?下面我整理了一下在Linux系统中如何查找大文件或文件 ...

  4. git操作:删除仓库中的文件或目录

    假定当前分支下,abc/123.txt需要从git仓库中删除: git .txt //删除abc目录下的123.txt文件,如果要删除abc目录,使用命令:git rm -r --cached abc ...

  5. 删除git中无用的大文件

    推荐阅读:为什么你的 Git 仓库变得如此臃肿 有时候我们不小心提交了一些大文件上去,后来删除了,但是已经于事无补了,整个git的提及已经蹭蹭上去了. 这个时候怎么办呢? 1. 查看有哪些大文件(to ...

  6. 快速清理maven仓库中下载错误的文件

    有时候使用pom文件下载依赖文件的时候突然网络异常,可能会出现依赖文件出现破损,导致怎么都不能使用,也没有重新下载. 之前解决办法是找到出现破损的文件并删除,让其重新下载,但是这样效率很低,也很难找到 ...

  7. 在python中逐行读取大文件

    在我们日常工作中,难免会有处理日志文件的时候,当文件小的时候,基本不用当心什么,直接用file.read()或readlines()就可以了,但是如果是将一个10G大小的日志文件读取,即文件大于内存的 ...

  8. 使用git在github远程仓库中操作

    在github上创建一个仓库,这一步参考廖雪峰老师的git教程,以及其他的一些准备工作略,我只记录几个重要的命令. 从其他github地址克隆项目 $ git clone git@github.com ...

  9. 忽略Git仓库中已经存在的文件

    解决方案 使用Git bash进入到要忽略的文件所在的文件夹,执行以下命令即可 git update-index --assume-unchanged rebel.xml 参考 Ignore Git ...

随机推荐

  1. 【Java每日一题】20170224

    20170223问题解析请点击今日问题下方的“[Java每日一题]20170224”查看(问题解析在公众号首发,公众号ID:weknow619) package Feb2017; import jav ...

  2. Hibernate入门(十)inverse

    双向关联产生多余的SQL语句 /** * 添加一个订单到id为6的客户中 */ @Test public void fun1(){ Session session = HibernateUtils.g ...

  3. linux 中的单引号 和双引号有什么区别吗

    单引号与双引号的最大不同在于双引号仍然可以保有变量的内容,但单引号内仅能是一般字符 ,而不会有特殊符号.我们以底下的例子做说明:假设您定义了一个变量, name=VBird ,现在想以 name 这个 ...

  4. Docker 系列三(容器管理).

    一.运行容器 1.基于镜像新建一个容器并启动 : tomcat:8.0 -i:交互式操作 -t:终端 -rm:容器退出后随之将其删除,可以避免浪费空间 -p :端口映射 -d :容器在后台运行 指明了 ...

  5. Python 字典(Dictionary) 基本操作

    Python字典是一种可变容器模型,可存储任意类型对象:如字符串.数字.元组等.它以键值对(key-value)的形式存在,因此相当于Hashmap在python中的实现. §1. 创建字典  字典由 ...

  6. js之单例模式

    单例模式是指一个类,只有一个实例.实现的思路是,创建实例时候加判断,如果有实例则返回,如果没有就new一个,并返回. 第一步: 创建类. function Waiter(id, name, salar ...

  7. idea代码提示

    idea代码提示:Keymap-->Main menu-->Code-->Completion去掉Cyclic Expand Word的快捷键将Basic的快捷键更改为Alt+/

  8. PHP7.27: pdf

    http://www.fpdf.org/ https://github.com/Setasign/FPDF https://www.ntaso.com/fpdf-and-chinese-charact ...

  9. FUNCTIONALITY OF ITEM CATEGORY

    Item Category Purpose This wiki page will breify discuss about functionality of Item Category in SAP ...

  10. mysql之外键

    本文内容: 什么是外键 外键的增加 外键的修改和删除 外键的约束模式 首发日期:2018-04-12 什么是外键: 外键就是表中存在一个字段指向另外一个表的主键,那么这个字段就可以称为外键. 一张表可 ...