14.2 暂存区操作引入的临时对象

暂存区操作有可能在对象库中产生临时对象,例如,文件反复地修改、反复地向暂存区添加,或者添加到暂存区后不提交甚至直接撤销,就会产生垃圾数据占用磁盘空间。为了说明临时对象的问题,需要准备一个大的压缩文件,10MB即可。

在Linux上与内核匹配的initrd文件(内核启动加载的内存盘)就是一个大的压缩文件,可以用于此节的示例。将大的压缩文件放在版本库外的一个目录上,因为这个文件会多次用到。


$cp/boot/initrd.img-2.6.32-5-amd64/tmp/bigfile

$du-sh/tmp/bigfile

11M/tmp/bigfile


将这个大的压缩文件复制到工作区中,复制两份。


$cd/path/to/my/workspace/i-am-admin

$cp/tmp/bigfile bigfile

$cp/tmp/bigfile bigfile.dup


然后将工作区中两个内容完全一样的大文件加入暂存区。


$git add bigfile bigfile.dup


查看一下磁盘空间占用:

工作区连同版本库共占用33MB。


$du-sh.

33M.


其中版本库只占用了11MB。版本库空间占用是工作区的一半。

如果再有谁说版本库空间占用一定比工作区大,可以用这个例子回击他。


$du-sh.git/

11M.git/


看看版本库中对象库内的文件,会发现多出了一个松散对象。之所以添加两个文件而只有一个松散对象,是因为Git对于文件的保存是将内容保存为blob对象中,和文件名无关,相同内容的不同文件会共享同一个blob对象。


$find.git/objects/-type f

.git/objects/2e/bcd92d0dda2bad50c775dc662c6cb700477aff

.git/objects/pack/pack-969329578b95057b7ea1208379a22c250c3b992a.idx

.git/objects/pack/pack-969329578b95057b7ea1208379a22c250c3b992a.pack


如果不想提交,想将文件撤出暂存区,则进行如下操作。

(1)查看当前暂存区的状态。


$git status-s

A bigfile

A bigfile.dup


(2)将添加的文件撤出暂存区。


$git reset HEAD


(3)通过查看状态,看到文件被撤出暂存区了。


$git status-s

?? bigfile

?? bigfile.dup


文件撤出暂存区后,在对象库中产生的blob松散对象仍然存在,通过查看版本库的磁盘占用就可以看出来。


$du-sh.git/

11M.git/


Git提供了git fsck命令,可以查看到版本库中包含的没有被任何引用关联的松散对象。


$git fsck

dangling blob 2ebcd92d0dda2bad50c775dc662c6cb700477aff


标识为dangling的对象就是没有被任何引用直接或间接关联到的对象。这个对象就是前面通过暂存区操作引入的大文件的内容。如何将这个文件从版本库中彻底删除呢?Git提供了一个清理的命令:


$git prune


用git prune清理之后,会发现:

用git fsck查看,没有未被关联到的松散对象。


$git fsck


版本库的空间占用也小了10MB,证明大的临时对象文件已经从版本库中删除了。


$du-sh.git/

236K.git/