3.Git 近乎所有操作都是本地执行,它的绝大多数操作都只需要访问本地文件和资源,不用连网。但如果用CVCS (集中式版本控制系统)的话,差不多所有操作都需要连接网络。且因为 Git 在本地磁盘上就保存着所有当前项目的历史更新,所以处理起来速度飞快。
cd .git拉出 .git 的目录列表,那么你至少能看到以下几个目录:
FETCH_HEAD/ HEAD/ config/ objects/ refs/现阶段我们需要聚焦的是objects目录,在objects中,我们最常见的对象是以下三种(具体的下文会详细说明这三者):
Blobs: 这是文件的内容,用于表示文件快照内容。
cd objects ls控制台展示:
// 堆代码 duidaima.com // 每个人的项目都不同,文件自然也不同,此处以笔者的一个项目为例 0c 57 85 b3 1b 60 94 c4 2a 67 98 cb 2c 6c 9a info 3c 73 a9 pack 49 82 af 52 83 b1小朋友你是否有很多问号?在第一眼看到这么多两位字符的文件夹名时完全不知道这些是啥。那么我们就需要转头来解释一下 Git 的数据存储结构 了。
objects ├── 0c │ ├── 8867d7e175f46d4bcd66698ac13f4ca00cf592 │ └── c8002da0403724dfaa6792885eaa97faa71bcf ├── 1b │ └── 716fafdd3aeb3636222a0026d1d4971078db05 ├── 2a │ └── 14f7db6a6748cc98862960ff5d0e9b1d4a2f17 ├── 2c │ ├── 14f7db6a6748cc98862960ff5d0e9b1d4a2f17 ├── 3c │ ├── 121291ffc25ce6792f9350883b77cea2633048 . . .为了验证上述 Git 存储对象的结构,我们可以查看当前最新的4次提交,并取第一条记录去提交记录的结构树中匹配:
command: git log -4 --oneline 9a5bf36 (HEAD -> master) feat: third commit 2c5331f feat: second commit 60814e1 feat: first commit 49942f3 Initial commit我们能看到最近的4次提交,并且每次提交都会有一个 7 位长的哈希值以及提交时的描述。以 9a5bf36 这次提交为例,我们可能会有个疑问:这只有 7 位似乎跟我们说的不太一样呀。别急!我们需要转换一下,将他转换成完整的长哈希值,因为在树结构中是以长哈希值构建生成的。
git rev-parse 9a5bf36Git 以等效的长哈希值响应:9a5bf367f10390c64a3f7b3e738b78bd78a3d781.
目录:9a 对象标识符:5bf367f10390c64a3f7b3e738b78bd78a3d781我们很容易就能看到找到:
objects ├── 0c │ ├── 8867d7e175f46d4bcd66698ac13f4ca00cf592 │ └── c8002da0403724dfaa6792885eaa97faa71bcf ├── 1b │ └── 716fafdd3aeb3636222a0026d1d4971078db05 . . . ├── 98 │ ├── ed6b3f02409778bc864d8897bc230c90cae445 ├── 9a │ ├── 5bf367f10390c64a3f7b3e738b78bd78a3d781 //====>在这 . .既然我们知道了它的存储结构,那么我们自然就应该打开这个文件查看文件的内容,但是我们不能直接查看此对象,因为 Git 中的对象是经过压缩的。如果您尝试使用cat 5bf367f10390c64a3f7b3e738b78bd78a3d781或类似方式查看它,您可能会看到一堆像这样的乱码,以及计算机尝试从二进制对象读取控制字符时发出的咔呲声:
6?$?(?E9?z??nUmV?Em]?p??3?`??????q?Ţqjw????VR?O? q?.r???e|lN?p??Gq?)?????#???85V?W6????? )|Wc*??8?1a?b?=?f*??pSvx3??;??3??^??O?S}??Z4?/?%J? xu?Ko?0??̯?51??Ԯ yB ??f?y?cBɯo?{ݝ?|ҌFL?:?@??_?0Td5?D2Br?D$??f?B??b?5W?HÁ?H*?&??(fbꒉdC!DV%?????D@?(???u0??8{?w ????0?IULC1????@(<?s ' mO????????ƶe?S????>?K8 89_vxm(#?jxOs?u?b?5m????=w\l? %?O??[V?t]?^??????G6.n?Mu?% ?̉?X??֖X v??x?EX???:sys???G2?y??={X?Ռe?X?4u???????4o'G??^"qݠ???$?Ccu?ml???vB_)?I? `??*ގF?of??O我们可以使用命令:
git cat-file -p 9a5bf36 sanqius-MacBook-Pro:3c zcy$ git cat-file -p 9a5bf36 tree 85b9416a23f8fb018181f96e5c01ba4bd923b965 parent 2c5331fd7046e561aad8fdde3e3f21375a17549c author 三秋 <sanqiu@***.com> 1665729807 +0800 committer 三秋 <sanqiu@***.com> 1665729807 +0800 feat: third commit我们看到的这个文件内部的这些内容其实就是一个对象,一个包含了 tree、parent、author... 等数据的对象,这个对象就是 Commits 了。
git cat-file -p 85b9416a23f8fb018181f96e5c01ba4bd923b965 100644 blob 0cc8002da0403724dfaa6792885eaa97faa71bcf README.md 040000 tree 3c121291ffc25ce6792f9350883b77cea2633048 src我们发现这个 Tree 对象下有两个,一个是 Blob 类型的 README.md 文件和 Tree 类型的 src 的文件夹,可以看出 Tree 是可以嵌套的,并且这个结构似乎有点眼熟,没错这就是我们项目的目录结构,这也就能解释为什么说 Commits 对象下的 Tree 就是对应着这个代码版本的文件快照了。(100644 代表它是一个普通的文件,100755 表示一个可执行文件,120000 仅仅是一符号链接)
git cat-file -p 0cc8002da0403724dfaa6792885eaa97faa71bcf MIT License Copyright (c) 2019 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell... <snip>我们可以看到其实这就是我们在这个代码版本下的文件内容,这也就意味着 Blob 其实就是存放文件的内容。
放一张图用来总结一下 Commits、Tree、Blob 三者之间的关系: