深入理解git内部原理

Git is a free and open source distributed version control system designed to handle everything from small to very large projects with speed and efficiency
上面这句话摘自git官网,意思是说git是一个分布式版本控制系统,快速高效的处理大小型项目的所有事情。那么git如何做到快速高效的呢。我们先写一个demo来演示一下效果,然后我们深入讲一下原理.

(操作这之前,需要自己在电脑上安装git,这里不再讲怎么安装git和命令的使用)

首先我们进到D盘,创建gitDemo这个文件夹,在这个文件夹下打开git,使用git init命令初始化一个git版本库
git init

在这里插入图片描述

我们在当前目录下创建一个以“hunter”命名的txt文件

在这里插入图片描述

在hunter.txt中写上点字

在这里插入图片描述

现在将他提交到git版本库
git add .
git commit -m "第一次提交"

在这里插入图片描述

这个时候我们创建一个新的分支,并切换到新的分支
git checkout -b dev
dev这个分支没有指定分支,则是在master(刚刚创建的)分支上创建的,则这时hunter.txt文件的内容还是"11111"

在这里插入图片描述

我们在dev分支上对hunter.txt文件进行改动然提交
将hunter.txt 内容由"11111"改为"22222"
git add .
git commit -m "第二次改动"

在这里插入图片描述

下面我们在切回到master分支
git checkout master

在这里插入图片描述

发现hunter.txt文件只有一个,但是该文件在每个分支的内容是不同的,那git内部是怎么存储的呢,接下来我们来分析git的原理。
在git内部维护了四个对象,分别是blob对象,commit对象,tree对象,tag对象。
我先来画一下这几个对象的关系,稍后我们代码演示一遍

在这里插入图片描述

当我们从工作空间 add 到暂存区之后,这时候每个被更改的文件会形成一个blob对象,blob对象里面的内容是原始内容的压缩,blob文件的文件名是根据原始内容的hash值。
当我们commit的时候,会形成一个或者多个tree对象和一个commit对象,到底形成几个是根据我们的文件目录层级来定的(一会我们演示的时候注意一下)。

在这里插入图片描述
在这里插入图片描述

最终这些对象将会保存在.git文件夹的objects里面

在这里插入图片描述

好了,上面这些暂时缓存在自己的大脑里,下面我们带着这些抽象的东西去coding印证一下
先介绍几个命令
 find .git/objects/ -type f       查看git里所有的object
 git cat-file -t #{对象名}         查看对象的类型
 git cat-file -p #{对象名}         查看对象的内容
我们重置一下git版本库,进入到d盘,新建gitDemo文件夹,在gitDemo文件夹下打开git命令窗口
git init

在这里插入图片描述

新建一个hunter.txt文件,在文件里随便写一些东西

在这里插入图片描述

add之前先用find .git/objects/ -type f 命令看一下目前有多少对象

在这里插入图片描述

没有对象,我们add一下
git add .

在这里插入图片描述

形成一个对象,我们看一下这个对象的类型
git cat-file -t 8b25206ff90e9432f6f1a8600f87a7bd695a24af

在这里插入图片描述

看一下文件里面存的什么,我们先直接进到这个文件里面打开,然后再用命令打开

在这里插入图片描述

打开文件之后,并不能看到里面到底存的是什么,这里印证了前面所说的blob里面存的是原始文件的压缩内容
再用命令打开看一下
git cat-file -p 8b25206ff90e9432f6f1a8600f87a7bd695a24af

在这里插入图片描述

确实是这个blob对象里面存储了我们的内容,下面我们commit到本地仓库,并且查看新形成的git对象
git commit -m "第一次提交"
find ./git/objects/ -type f

在这里插入图片描述

此时多了两个对象,我们分别用命令查看一下他们分别是什么类型的对象,以及对象里的内容

在这里插入图片描述

到这里你是不是发现了点什么,对着这张图屡一下

8b25206ff90e9432f6f1a8600f87a7bd695a24af 是blob对象,里面存储了具体的消息内容
a8d587b2fc8e2067f6f6a080268d8412332a2875 是tree对象,里面存储了blob的hash值,以及blob对象真实的文件名字
55b9744d8955c92dc57f3bf63bf6aaf284dfd47e 是commit对象,里面存储了tree的hash值,提交时备注内容,作者等信息

到此我们实现了一个简单的git结构,git每一次选择分支,回滚都是怎么做的呢,继续来看
在.git文件夹下还有一个refs文件夹,这里面存储了所有的分支信息和tag信息

在这里插入图片描述

为了更好的区分我有新建了一个dev分支
git checkout -b dev

在这里插入图片描述

这些分支里面存的其实就是commit的值

在这里插入图片描述

明白了,其实git里每一个分支是一个文件,这个文件里保存着commit的值,根据commit的值找到tree,然后拿出来tree中所有的子tree和blob来展现所有的内容,问题又来了,那我肯定有一个地方标记当前工作空间所在的分支吧。莫急,这个标记的地方就在git文件夹下的head文件。

在这里插入图片描述

到这我们完全明白 工作空间根据git文件加下的head文件找到当前的分支,然后拿到分支进一步拿到commit从而得到所有的内容。
但是还有点什么东西需要注意一下小编直接告诉你这些,你可以自己coding验证。

①blob的形成是根据内容来形成的,换句话说如果我有两个文件A和B,A中的内容为“master”,B中的内容也是"master",提交时则只会形成一个blob对象。反过来,如果内容不一样则会形成两个blob对象。
②每一次add的时候,只有变化的文件才会形成新的blob并且原来的blob依然存在。
③每一次commit都会绘制一个新的tree,并且不复用之前的子tree,但是blob不会变。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值