一开始我还担心 git 的原理会不会很难懂,但在阅读了官方文档后我发现其实并不难懂,似乎可以动手实现一个简单的 git,于是就有了下面这篇学习记录。 本文的叙述思路参照了官方文档Book的原理介绍部分,在一些节点上探讨代码实现,[官方文档链接](
)。 看完本文你能:1. 了.解 git 的设计思想。2. 收获一点快乐? > 编程语言选择了 go,因为刚学不太熟悉想多使用一下。 这是我的仓库地址,但如果你和我一样是初学,直接看代码可能不能快速上手,推荐顺着文章看。 [迷你git实现--链接](
) > 如果文章看得吃力可以跟着官方文档的原理部分操作一次再回头看,可能更易懂? # 1. init 在学习 git 原理之前,我们先忘掉平时用的 commit,branch,tag 这些炫酷的 git 指令,后面我们会摸清楚它们的本质的。 要知道,git 是 Linus 在写 Linux 的时候顺便写出来的,用于对 Linux 进行版本管理,所以,记录文件项目在不同版本的变更信息是 git 最核心的功能。 大牛们在设计软件的时候总是会做相应的抽象,想要理解他们的设计思路,我们就得在他们的抽象下进行思考。虽然说的有点玄乎,但是这些抽象最终都会落实到代码上的,所以不必担心,很好理解的。 首先,我们要奠定一个 ojbect 的概念,这是 git 最底层的抽象,你可以把 git 理解成一个 object 数据库。 废话不多说,跟着指令操作,你会对 git 有一个全新的认识。首先我们在任意目录下创建一个 git 仓库: > 我的操作环境是 win10 + git bash ```shell $ git init git-test Initialized empty Git repository in C:/git-test/.git/ ``` 可以看到 git 为我们创建了一个空的 git 仓库,里面有一个`.git`目录,目录结构如下: ```shell $ ls config description HEAD hooks/ info/ objects/ refs/ ``` 在`.git`目录下我们先重点关注 `.git/objects`这个目录,我们一开始说 git 是一个 进入`.git/objects`目录后我们能看到`info`和`pack`两个目录,不过这和核心功能无关,我们只需要知道现在`.git/objects`目录下除了两个空目录其他啥都没有就行了。 > 到这里我们停停,先把这部分实现了吧,逻辑很简单,我们只需要编写一个入口函数,解析命令行的参数,在得到 init 指令后在指定目录下创建相应的目录与文件即可。 这里是我的实现:[init](
/tree/b5e0f0ed8005436af182b454d6717ef3841bd5d3) 为了易读暂时没有对创建文件/目录进行错误处理。 我给它取了个土一点的名字,叫 jun,呃,其实管它叫啥都可以`(⊙ˍ⊙)`。 # 2.object 接下来我们进入 git 仓库目录并添加一个文件: ```shell $ echo "version1" > file.txt ``` 然后我们把对这个文件的记录添加进 git 系统。**要注意的是**,我们暂不使用`add`指令添加,尽管我们平时很可能这么做,但这是一篇揭示原理的文章,这里我们要引入一条平时大家可能没有听到过的 git 指令`git hash-object`。 ```shell $ git hash-object -w file.txt 5bdcfc19f119febc749eef9a9551bc335cb965e2 ``` 指令执行后返回了一个哈希值,实际上这条指令已经把对 file.txt 的内容以一个 object 的形式添加进 object 数据库中了,而这个哈希值就对应着这个 object。 为了验证 git 把这个 object 写入了数据库(以文件的形式保存下来),我们查看一下`.git/objects`目录: ```shell $ find .git/objects/ -type f #-type用于制定类型,f表示文件
