查看原文
其他

这个 git 命令你每天都在用,但你却不知道

The following article is from 神光的编程秘籍 Author 神说要有光zxg

在团队开发中,我们每天都在敲 git clone、add、commit、push 这些命令,其实它们涉及到一个底层命令。

这个命令你每天都在用,每天都能看到它的输出,但你却不知道你用到了这个命令。

那这个命令是啥呢?

git 存储内容是通过 object 的形式,文件内容是 blob 的 object,目录是 tree 的 object,commit 就是 commit 的 object。

这三种 object 串联起来就是 git 存储的内容了。

然后 branch 和 tag 都是指向 commit 对象的指针。

也就是这样:

这就是 git 的存储原理。

在 .git 目录下可以看到所有这些 object:

你 git clone 和 push 的时候,其实也就是下载 object:

但修改同一个文件,只是改了一点也会创建一个新的 object,因为 hash 变了。

如果整个大文件就改了一点东西,却把整体都保存为一个新的 object,岂不是太浪费空间了?

没错,git 自然也想到了这点,所以它会做压缩。

怎么压缩的呢?

你可以执行 git gc 这个命令来体验下压缩过程。

比如 text.txt 这个文件,我先 git commit 一次。

然后把最后一行改为 bbb,git commit 一次。再改为 ccc 再 git commit 一次。

这时候有 9 个 object:

因为 3 次内容变动会有 3 个 blob 类型的 object,然后有 3 个 tree object 来指向它们,还有 3 个 commit object。

比如其中一个 tree object 的内容是这样的:

(cat-file -p 就是查看对象内容的命令)

它指向一个 blob 对象。blob 对象内容是这样的:

而这个 tree 对象也有 commit 对象指向它:

这就是 3 种对象的关系。

我们跑下 git gc 看看会发生什么:

输出内容如上,是不是有种莫名的熟悉感?

为什么有熟悉感待会再说,我们先来看看它都做了什么。

你会发现执行完 gc 后 objects 下都没有那些对象了,但是在 pack 目录下多了一个 idx 文件和一个 pack 文件。

这就是压缩打包后的结果。

咋压缩的呢?

看下它的内容就知道了:

执行 git verify-pack -v 看下 idx 文件的内容:

你会看到 3 个 commit、3 个 blob、3 个 tree 对象都列出来了,而且 3 个 blob 对象之间还有指向关系,也就是这个:

叫做 chain。

这是啥呢?

其实 pack 里就是打包后的 object,然后 idx 记录着不同文件在其中的位置。

但是总不能把同样的文件原封不动保存多份吧。

所以 git 会对内容相近的文件做 diff,只保留一个版本的全部内容,其余的都是保存 diff。

那保存哪份呢?

用 cat-file -p 看看它的内容:

发现是保存的最后那个版本的全部内容,之前的版本保存 diff。

原因很容易想到,最新的肯定用的最频繁嘛,这样处理起来也方便。

这就是 git gc 压缩的原理(gc 是 garbage collection,垃圾回收的意思)。

那这个命令和 git clone、git push 有啥关系呢?

你再瞅瞅它的输出看看:

是不是很熟悉?

对比下 git push 的输出:

是不是一毛一样!

没错,在 git push 之前,git 会执行 git gc 来压缩打包再传输。

再来看看 git clone 的输出:

同样能看到 git gc 的身影。

没错,在 git clone 的时候,服务端也会执行 git gc 再传输。

所以 git gc 这个命令你每天都在用,每天都能看到它的输出,但你却不知道它的存在。

总结

git 通过 blob 存储文件内容,tree 存储目录信息,commit 存储提交信息,这 3 种对象关联起来就是 git 的存储原理。

但是同样的内容保存多个类似的 object 是没必要的,git 自然也做了处理,就是 git gc 命令,它会把所有 object 打包到一起,并且类似的内容只会保留最新的那个,其余的只保存 diff。

其实你每天都能看到 git gc 的身影,尤其是你执行 git clone、git push 命令的时候。

下次再 clone、push,你能想起这个 git gc 了么?

往期推荐

我的学习小圈子

让程序员老弟去做 PPT?白日做梦

再见了,腾讯!

我只用一个接口实现 CRUD,可能么?

自我介绍,千万别来虚的!

出息了,自己做一个短链服务

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存