开发者学堂课程【Git 从入门到进阶: Git 的十年变化(二)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1194/detail/18116
Git 的十年变化(二)
内容介绍:
一、Git Objects
二、Git References
三、Speed up operations on git objects and references
一、Git Objects
从第二期开始,将主要通过幻灯片讲解配合命令操作的方式来进行,将从 Git 的基础知识和概念作为切入点开始介绍,因为基础知识和概念是很重要的,对后续视频的了解和学习也会很有帮助。随着后续视频的推出,大家会越来越深入的了解 Git 的奇妙世界。本期介绍三部分的内容,第一部分内容介绍 Git 中的 objects,也就是 Git对象。第二部分内容会介绍 Git 中的references,也是 Git 的引用。最后一部分内容是针对 git objects和 references 介绍一些初级的仓库清理方法。
1、Git Objects
Git 是一款版本控制 (VCS) 工具
Git Objects 近乎存储了Git 的一切
Git 目前有哪些不同的对象类型?
Git 不同类型的对象之间有什么关系?
Git 是一款分布式版本控制工具,所以自然而然需要存储大量的文件内容数据,Git objects 在其中发挥了非常关键的作用。Git 经过了16年的发展过程中诞生了很多令开发者惊叹的特性,但 Git objects 的核心理念几乎却没有任何变化,其重要程度可见一斑。Git objects 几乎存储了 Git 的一切,多种类型的对象和对象之间的引用共同构成了 Git 版本控制的核心。所以了解 Git objects 是用好 Git 的重要基础。
2、Git objects 的存储特点
Git Objects 通常存储在仓库的 .git/objects/ 目录下。
Git Objects 是通过 key-value 的形式进行存储。
不同的 Object,Git 会为其自动生成唯一的 key。
Key 的格式为 SHA1,为40-digit hexadecimal (新版本 Git 还可支持 SHA256,为 64-digit hexadecimal)。
Git objects 会松散存储在 .git/objects/ 目录下,Git objects 本质是 key-value 的形式进行存储。针对不同的 Object,Git 会为其自动的生成唯一的key,Key 的格式为 SHA1,它的表示为40位的16进制字符串。在新版本的 Git 中还可以支持 SHA256的格式为64位的16进制字符串。
3、实操演示
简单的操作看 Git Objects 的存储方式
/tmp git init test
Initialized empty Git repository in /private/tmp/test/.git/
/tmp cd test
test git:(master) find .git/objects -type f
test git:(master) ccho 'Hello World’I git hash-object -w-stdin 557db03de997c86a4a828e1ebd3a1ceb225be238
test git:(msster) find .git/objects -type f
.git/objects/55/7db85de997c86a4a828e1ebd5a1ceb225be258
test git:(master)
首先执行 git init 命令,创建一个初始化的 Git 仓库,进入到仓库目录当中执行 find 命令,然后尝试用 git hash-object 子命令来创建一个真实的对象,执行。这条命令将会返回一个对象的 Key,从此对应的一个对象就有它的身份证,其次 git hash-object-w 的参数可以让命令不只来输出 key值,同时还会将对象真实的写入到Git 仓库中。--stdin 选项告诉其通过输入流来读取文件内容。可以通过不指定输入流的方式,而直接指定文件名的一个方式,也可以达到这样的目的。最后整条命令实际上是通过一个管道将文件内容的产生过程和内容对象的存储过程结合起来,随后可以再次执行 find 命令,可以发现当前在 Git objects 下面已经有了新的目录和文件,已经代表这个对象已经成功保存在了 Git 仓库当中,这是 Git 在仓库中存储对象的方式,将 key 的前两位作为目录名存储,更有利于离散查找的效率。将剩余的38位来作为真实的对象文件名来进行存储。
4、Git Objects 的类型区分
Git Objects 包含4种类型:Blob | Tree | Commit | Tag
Blob: 负责存储文件内容. - Tree:目录索引.
Commit:提交元信息(作者、提交者、说明、父提交等)并关联一个目录索引视图(root-tree)
Tag: 记录重要历史时刻的提交节点和相关信息(一般用于标记发行版).
Git Objects 包含了四种不同类型的对象,分别为 blob、tree 、commit 和 tag,blob 对象用于存储文件的内容,例如刚才使用的git hash-object 命令是在仓库中,保存了一个内容为 hello world的 blob 对象,Tree 对象则负责进行目录的索引,它保存了某个目录下的一个完整的视图。Commit 对象负责存储提交的元数据,例如作者、提交者、提交说明和父提交的信息,同时 commit 还会引用一个根目录的索引视图,通常叫 root-tree。Tag 对象是负责记录重要的历史时刻的提交和相关的注解信息,一般用于标记发行版。
5、实操演示
/tmp git init test
Initialized enpty Git repository in /private/tmp/test/.git/
/tmp cd test
test git:(master) echo 'readme’> README.nd
test git:(master) x git add README.nd
test git:(master)x git commit -s
[master(root-commit)0282745]CommitA
1 file changed, 1 insertion(+)
create mode 108644 README.nd
test git:(master) find .git/objects -type
.git/objects/02/827453dbbeafc869581e12b2968b11dafabf45
.git/objects/81/78c76d627cade75005b40711b92f4177bc6cfc
.git/objects/76/4409de08fa4fda9ba6c85a54f5f31d00cec93e
test git:(master)
test git:(master) nkdir src
test git:(master) mkdir docs
test git:(master) echo "abc"> src/main.c
test git:(master) echo "efg"> docs/project.txt
test git:(master) git add src
test git:(master) x git add docs
test git:(master) x git commit-s
[master 5eb450d] Commit B
2 files changed, 2 insertions(+)
create mode108644 docs/project.txt
create mode 108644 src/main.c
test git:(master) git tag -a -m "Release V1.0" v1.0
test git:(master) git log
首先初始化一个仓库,进入到仓库的目录中,通常工程第一个都会有一个 README 文件,然后也创建一个 README 文件,创建了一个 README.md 文件,然后执行 git add README.md 然后 git commit-s,因为演示提交信息写的随意一些,叫 Commit A,通过find 命令可以看到操作下来 Git 一共生产了三个文件,其中一个文件保存 blob 对象,用来存储的 README.md 文件内容,另外生成了一个 root-tree 对象,对象保存当前整体目录的索引。最后一个对象是 commit 本身,README.md 文件写好之后开始写代码,首先创建一个 src 目录,用来存放源码,然后创建一个 docs 目录来存放工程文档,在 src 目录下面新建一个 main.c 的文件,随意输出一些内容,新建一个 docs 文件,把它存放在 docs下面的project.txt 中,直接 git add src,git add docs 然后执行 git commit,叫做 commit B
Commit B
Signed-off-by: Dyrone Teng <tenglong.tipalibaba-inc.coms
Please enter the connit messoge for your changes. Lines starting
with "#’will be ignored, and an empty message aborts the comnit.
On branch naster
Changes to be committed:
new file: docs/project.txt
new file: src/main.c
最后再创建一个 tag,记录一下 tag 的注解息,记录成1.0版本。Tag 名叫做 V1.0,最后通过 git log 查看 commit
commit 5eb458d14ff87bdbadd8b8376a597647f448934e(HEA D master ng:v1.0)
Author: Dyrone Teng <tenglong.t&alibaba-inc.com
Date: Sat Sep 18 15:15:58 2021 +8800
Conmit B
Signed-off-by: Dyrone Teng <tenglong.tlgalibaba-inc.com>
commit 82827455dbbeafc869581e12b2968b11dafabf45 Author: Dyrone Teng <tenglong.tugalibaba-inc.comp
Datei Sat Sep 18 15:13:57 2021 +8880
Commit A
Siqned-off-by: Dyrone Teng <tenglong.tlealibaba-inc.comp[END)
6、Git Objects 的组织关系
上面操作 Git 总共创建了七个对象,包含两个 biob 对象,用于存放 main.c 和 project.txt 的文件内容,包含三个 tree 对象,两个Tree 对象用于存储 src 和 docs 目录的索引视图,另外一个作为 root-tree 用于存储根目录的全局视图,另外还有一个 commit 对象用于记录本次提交的元数据,并且使其指向新创建的 root-tree,最后还会设置新提交的父提交 commit A,另外还创建了一个具备注释信息的 tag' 对象。对于 readme.md 文件,因为在本次的提交没有对其进行任何的更改,并不会创建一个新的 blob 对象去存储它,而是选择直接引用原来创建的 biob 对象。通过演示对 Git objects 背后的存储模式有大体的了解,事实上 Get objects 存储并非只有松散存储为单个文件的形式。
二、Git References
Git 对象的名片:References
Git references如何存储?
Git 目前有哪些引用类型?
Git references 也是 Git 引用,Git 对象是用 SHA-1 或者 SHA-256 的格式来存储。格式的表示形式对于使用 git 非常不方便,引用是为此而生,在很多版本控制系统当中都引用的概念,所以并不是 Git 独有的设计, Git 对象的名片 Git references。
1、Git references 存储与更新
Git references 通常存储在仓库的 .git/refs/ 目录下.
Builtin Git references
Branches: refs/heads/<branch>
Tags: refs/tags/<tag>
Remotes: refs/remotes/<origin>/<ref>
Symbolic reference: HEAD
更新引用
方式1:echo <SHA-1> >.git/refs/heads/topic_aliyun
推荐方式:git update-ref refs/heads/topic_aliyun <SHA-1>
Git 引用存储有几个特点,第一 Git references 是存储在 .git/refs目录下。第二 Git 支持 4 种默认的 Builtin reference,分别为branches,branches 作为分支的应用存储在 .git/refs/heads 目录下,tags 作为标签引用存储在 .git/refs/tags 目录下,Remotes作为与远端协作时使用,存储在 .git/refs/remotes 目录下。最后一个 HEAD 作为一个符号引用,存储在 .git 目录下。另外可以通过很多不同的方法来创建和更新引用,方式一因为 ref 也是在 git 仓库中进行松散存储形式,所以可以直接创建对应的 ref 文件,例如使用 echo 命令写入 ref 文件,方式一在真正的场景当中不是非常的安全,为此 git 专门设计了一个 update-ref 的命令,可以用来维护仓库中的引用信息,通过 git update-ref 命令可以非常轻松的创建、更新和删除仓库中的应用。
2、实操演示
(1)Commit A
commit 5eb450d14ff87bdbadd0b8376a597647f440934e(HEA D master, tag:v1.0, topic_aliyun)
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:15:58 2021 +0880
Comnit B
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
commit 02827453dbbeafc869581e12b2968b11dafabf45 Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:13:57 2021 +0800
Comnit A
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
选择比较老的 commit A 来创建 reference
/tmp git init test
Initialized enpty Git repository in /private/tmp/test/.git/
/tmp cd test
test git:(master) echo 'readme’> README.nd
test git:(master) x git add README.nd test git:(master) x git commit -s
[master (root-commit)0282745] Commit A
1 file changed, 1 insertion(+) create mode 108644 README.nd
test git:(master) find .git/objects -type
git/objects/02/827453dbbeafc869581e12b2968b11dafabf45 git/objects/81/78c76d627cade75005b40711b92f4177bc6cfc git/objects/76/4409de08fa4fda9ba6c85a54f5f31d00cec93e
test git:(master)
test git:(master) nkdir src
test git:(master) mkdir docs
test git:(master) echo "abc"> src/nain.c
test git:(master) echo "efg" >i docs/project.txt
test git:(master) git add src
test git:(master) git add docs
test git:(master) x git commit -s
[master 5eb458d] Commit B
2 files changed,2 insertions(+)
create mode 100644 docs/project.txt
create mode 108644 src/main.c
test git:(master) git tag -a -m "Release V1.0" v1.0
test git:(master) git log
test git:(master) git log
test git:(master)echo 02827453dbbeafc869581e12b2968b11 dafabf45 >.git/refs/heads/topic_aliyun
test git:(master) git log topic_aliyun
可以执行 echo,hash 写到 gitrefs/heads,选择创建一个分支的引用取名为 topic_aliyun,选择执行 git log topic_aliyun,发现已经可以查看引用的提交信息,并且它的信息已经成功记录到 Commit A。
commit 02827453dbbeafc869581e12b2968b11dafabf45(topi c_aliyun)
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:13:57 2821 +0880
Comnit A
signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
(END)
(2)Commit B
commit 5eb450d14ff87bdbadd0b8376a597647f440934e(HEA D master, tag:v1.0, topic_aliyun)
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:15:58 2021 +0880
Comnit B
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
commit 02827453dbbeafc869581e12b2968b11dafabf45 Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:13:57 2021 +0800
Comnit A
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
继续通过第二种方式来进行先查找一下 Commit B的 hash
/tmp git init test
Initialized empty Git repository in /private/tmp/test/.git//tmp cd test
test git:(master) echo 'readme’> README.nd
test git:(master) x git add README.nd
test git:(master) x git commit -s
[master(root-commit)6282745]CommitA1 file changed, 1 insertion(+) create mode 108644 README.nd
test git:(master) find .git/objects -type f
.git/objects/82/827453dbbeafc869581e12b2968b11dafabf45 it/objects/81/78c76d627cade75005b40711b92f4177bc6cfc
.git/objects/76/4409de08fa4fda9ba6c85a54f5f31d00cec93e
test git:(master)
test git:(master) nkdir src
test git:(master) nkdir docs
test git:(master) echo "abc"> src/nain.c
test git:(master) x echo "efg" > docs/project.txt
test git:(master) x git add src
test git:(master) x git add docs
test git:(master) x git commit -s[master 5eb450d] Commit B
2 files changed, 2 insertions(+) create mode 100644 docs/project.txt create mode 100644 src/main.c
test git:(master) git tag -a· "Release V1.0" v1.0
test git:(master) git log
test git:(master) git log
test git:(master) echo02827453dbbeafc869581e12b2968b11d afabf45 >.qit/refs/heads/topic_aliyun
test git:(master) git log topic_aliyun
test git:(master) git log
test git:(master) git update-ref refs/heads/topic_aliyun 5eb45 0d14ff87bdbadd0b8376a597647f440934e
test git:(master) git log topic_aliyuntest git:(master)
test git:(master) git remote add git@codeup.aliyun.com:rdc2 020/first_repo.git usage: git renote add [<options>] <name> <url>
-f,--fetch fetch the renote branches
--tags import all tags and associated objects when fetching
or do not fetch any tag at all (--no-tags)
-t, --track <branch> branch(es)to track
-m,--naster <branch>
master branch
--mirror[=(push|fetch)]
set up renote as a mirror to push to or fetch from
test git:(master) git remote add origin git@codeup.aliyun.com: rdc2020/first_repo.git
test git:(master) git remote -v
origin git@codeup.aliyun.com:rdc2020/first_repo.git(fetch)
origin git@codeup.aliyun.com:rdc2020/first_repo.git (push)
test git:(master) git push origin topic_aliyun
Enumerating objects: 9,done.
Counting objects: 100k(9/9),done.
Delta compression using up to 8 threads
Compressing objects:100%(3/3),done.
Writing objects: 180% (9/9), 751 bytes | 751.08 KiB/s, done. Total 9 (delta 1), reused 0 (delta 8), pack-reused e
To codeup.aliyun.com:rdc2020/first_repo.git
* [new branch] topic_aliyun→topic_aliyun
test git:(master)
test git:(master) .git/refs/remotes/origin/topic_aliyun5eb450d14ff87bdbadd8b8376a597647f440934e
test git:(master) git log
然后执行 get update-ref refs/heads/topic_aliyun 的 hash 值,再次执行 git log topic_aliyun,可以发现版本已经被正常更新。
commit 5eb450d14ff87bdbadd0b8376a597647f440934e(HEAD master, tag: v1.0, topic_aliyun)
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:15:58 2021 +0880
Comnit B
Signed-off-by: Dyrone Teng<tenglong.tldalibaba-inc.com>
commit 02827453dbbeafc869581e12b2968b11dafabf45
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:13:57 2021 +0800
Comnit A
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
(END)
继续了解一下 remotes 的 refs,首先在仓库中添加一个仓库的remote,可以执行get remote add,云效 code up 上面的一个代码仓库 git remote add origin,添加 remote,可以执行 remote-v 来查看,当时已经添加了一个 origin 的 remote,执行 git push origin topic_aliyun,把分支的引用推到远端的仓库上,可以看到已经推送成功,可以查看 .git/refs/remotes/origin/topic_aliyun remote 的 refs,可以看到已经正确记录刚才推送的版本,所以通过这种方式 git 可以知道本地的相对于远端 server 上最后一个已知的版本情况,最后执行 git log 不加任何参数,可以看到正常的提交历史。
cormit 5eb450d14ff87bdbadd0b8376a597647f440934e (HEAD naster origin/topic_aliyun, topic_aliyun)
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:15:58 2021 +8880
Commit B
signed-off-by: Dyrone Teng g<tenglong.tldalibaba-inc.com>
commit 02827453dbbeafc869581e12b2968b11dafabf45
Author: Dyrone Teng <tenglong.tl@alibaba-inc.com>
Date: Sat Sep 18 15:13:57 2021 +0880
Comnit A
Signed-off-by: Dyrone Teng <tenglong.tl@alibaba-inc.com>
(END)
3、了解不同类型的 Git references
Branches:refs/heads/<branch> Conmit Parent Conmit B
Symbolic reference:HEAD
(git symbelic-ref HEAD)
Tags:refs/tags/<tag>
Remotes: refs/remotes/<origin>/<ref>
大致了解了分支、标签和远端用几种类型。在操作最后直接执行了 git log 命令,执行的过程没有指定任何 commit 和 reference 作为log参数,最终该命令是可以正常执行的,而且仍旧可以帮助来查看最近一次提交的相关信息。Git 知道最后一次提交信息是在符号引用上面,简单概括符号引用就是指向引用的引用,HEAD 就是一个特殊的符号引用,HEAD 被设计为负责指向当前所在分支的引用,感兴趣可以查看一下仓库中 .git 下面的 HEAD 文件内容便会立刻找到答案。也可以使用命令 git symbol-ref HEAD 来查看 HEAD 符号引用的相关信息。
三、Speed up operations on git objects and references
对象和引用存储方式带来的性能问题。
引用提速:.git/packed-refs 文件和 git pack-refs 命令
对象提速:git repack 命令和 git gc 命令
因为 Git Objects 和 References 默认是通过松散文件的形式来存储的,随着在仓库中的数目变得越来越多,仓库也会变得越来越慢。在第三部分介绍简单的对象和引用的清理方法。
1、大量对象和引用带来的仓库性能问题
1.04M
COMMITS
4.98M
TREES
2.32M
BLOBS
712
REFERENCES
git@github.com:torvalds/linux.git
使用 Git 管理代码非常知名的仓库,Linux kernel 仓库,在 Linux仓库中,总共包含了超过100多万个 commit 对象,接近于500万个 tree 对象和232万个 biob 对象。如果这么多的对象都通过松散的方式存储在 Git 仓库中,仓库中针对对象的操作性能会非常的差,对于引用也一样。
2、简单的仓库清理命令
(1)为 Git Objects | References 读取提速
使用 git pack-refs 命令,打包松散引用,打包后的文件为 .git/packed-refs 文件
使用 git repack 命令,打包松散对象为 Pack 文件
使用 git gc 命令,完成一键清理
(2)Note
针对不同的 Git 大仓场景,Git 存在多种解决方式,并非三言两语可以讲清。
例如:git-multi-pack-index, bitmap,commit-graph, git-LFs,partial-clone等等。
首先是 git pack-refs 命令,该命令可以实现更高效的引用访问,在默认情况下,每个 ref 都会单独的存储为一个文件,当仓库有成百上千的文件时,这种存放的方式既浪费了存储空间又拖拉的性能,pack-refs 令通过将 refs 数据存储在单个文件中来解决场景下的存储和性能问题,单个的文件最终会保存在 .git/packed-refs 文件当中,同样跟 refs 一样,objets 的存储也存在这样的问题,同样可以通过 git repack 命令将松散对象打包成一个 pack 文件,从而提升对象访问的性能。Pack 文件也是 git 中一个比较核心的数据结构,最后 git gc 命令做了非常多的事情,既可以是 pack-refs 和 repack 的组合拳方式,同时也可以清除 git 仓库中的不可达对象,或者删除一些历史的 reflog,更新 commit-graph 等等。Git 大仓的问题一直以来是 git 技术领域的核心话题,针对不同的 Git 大仓库场景,git 存在非常多的解决方式,不容易讲清楚,例如 git-multi-pack-index bitmap commit-graph git-LFS partial-clone 等等,都在一定程度上解决了仓库过大的问题所导致的性能问题。这些内容实际上需要建立在对 Git 基础概念和基础知识非常了解的情况下才能进行学习。
3、实操演示
test git:(master) -ltra
total 8
-rw-r--r-- 1 tenglong.tl wheel 9 18 15:13 README.md
drwxr-xr-x 6 tenglong.tl wheel 192 9 18 15:15
drwxr-xr-x 3 tenglong.tl wheel 96 9 18 15:15 src
drwxr-xr-x 3 tenglong.tl wheel 96 9 18 15:15 docs
drwxrwxrwt 21 root wheel 672 9 18 16:12
drwxr-xr-x 13 tenglong.tl wheel416 9 18 16:25 .git
test git:(master) find .git/refs -type f
git/refs/heads/topic_aliyun
git/refs/heads/master git/refs/tags/v1.0
git/refs/remotes/origin/topic_aliyun
test git:(master) git pack-refs --all
test git:(master) find .git/refs -type
test git:(master) cat.git/packed-refs
pack-refs with: peeled fully-peeled sorted
5eb450d14ff87bdbadd8b8376a597647f440934e refs/heads/master
5eb458d14ff87bdbadd8b8376a597647f448934e refs/heads/topic_aliyun
5eb450d14ff87bdbadd0b8376a597647f448934e refs/remotes/origin/topic_aliyun86aeba4cdfea355baf052131736c3af6fa25d59crefs/tags/v1.0^5eb450d14ff87bdbadd0b8376a597647f440934e
test git:(master) find .git/objects -type f
git/objects/82/827453dbbeafc869581e12b2968b11dafabf45 git/objects/81/78c76d627cade75005b40711b92f4177bc6cfc git/objects/86/aeba4cdfea355baf052131736c3af6fa25d59c git/objects/5e/b450d14ff87bdbadd0b8376a597647f448934e git/objects/99/b20b290a90e1137e8487f955620db05b229abe git/objects/8d/b636fa1dbc4d704179895bdb6e4322f32cbda6 git/objects/15/85b408c2ef47655f603b9045464e642ab28d97 git/objects/76/4409de08fa4fda9ba6c85a54f5f31d00cec93e git/objects/2e/6cdc032db0ecfa4e3e898b8f8551acce10db11 git/objects/8b/aef1b4abc478178b004d62831cf7fe6db6f983 test git:(master) git repack -d Enumerating objects: 10, done.
Counting objects: 100%(10/10), done. Delta compression using up to 8threads Compressing objects:100%(4/4),done. Writing objects: 100%(10/18), done.
Total 10 (delta 1), reused 0 (delta 0), pack-reused e
test git:(master) find .git/objects -type f
git/objects/pack/pack-b84690ccd577fc81809bcfd120d4040332af69f2.pack git/objects/pack/pack-b84690ccd577fc81809bcfd120d4040332af69f2.ilx
git/objects/info/packs
test git:(master)
首先尝试打包松散的引用,先执行 find 命令,当前仓库中有如下几个引用,可以直接 git pack-refs--all,--all 的选项是告诉 pack-refs 将所有的 tag 和分支全部进行打包,在执行之后再次执行 find 命令,发现 refs 目录下已经没有引用文件,查看一下 .get 下面的 pack-refs 文件,可以看到已经把引用对应的信息全部打包到 packrefs 单个文件当中。下一步将演示 repack 命令,首先执行 find 命令,看当前仓库中有哪些松散的对象 .git/objects 可以看到当前 git objects下面有如下很多的对象,随后执行 git repackd,-d 的参数是告诉 repack 命令,如果这些散对象和已经打包好的 pack 文件当中的对象存在重复的对象,就会把这些重复的松散对象,从 git 仓库当中去删除。执行成功之后再执行find 命令,在当前 objects 目录下的对象已经没有,现在暂时在 pack 的子目录当中产生了 pack 文件和对应的索引文件。
4、彩蛋
(1)仓库中做一个提交,包含一个名为 src/mainc 的文件,共有几个对象?
(2)Git 对象的内容均使用了 zlib 压缩,我们可以使用 git cat-file命令获取对象信息。
-t Instead of the content, show the object type identified by <object>
-S Instead of the content, show the object size identified by <object>
-p Pretty-print the contents of <object> based on its type
(3)Git Tree 对象包含的文件条目实际还存储了 filemode,比如:
180644 Normal File
100755 Executable File
120888 Symbolic link
840988 Dir
(4)Git 仓库中的对象统计信息可以使用 qit-sizer 计算,前面对Linux 对象的统计便是通过此方法计算得出。
https://github.com/github/git-sizer
其包包含一个名为 src main.c 的文件总共包含几个对象。第二 git对象的内容均使用了 zlib 进行压缩,但可以使用 git cat-file 命令来获取对象信息。当使用 -t 参数的时候,可以获取对象的类型,当使用 -s 参数的时候可以获取对象大小,当使用-p 参数的时候,可以结构化的输出对象内容。第三 Git Tree 对象包含的文件条目,实际上还存储了 filemode,例如可以是普通文件、可执行文件、符号链接以及目录,所以当修改了文件的类型和权限,或者也叫做 file attributes 的时候,git 默认也会认为文件产生了变化。第四 git 仓库对象的统计可以使用 git-sizer 进行计算。对 linux 仓库的对象统计是通过该工具来完成的。