记一次删除Git纪录中的大文件的历程

最近在开辟一个新运用,有一天在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 --all
git gc --prune=now

至此,我们已完全的删除了我们不想要的文件。

原文链接

    原文作者:快乐动起来
    原文地址: https://segmentfault.com/a/1190000015834388
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞