git内部原理浅见

文中内容可能存在错误,仅供参考,切勿全信。

git目录结构

  • .git/objects : 存放对象(blob, tree, commit, tag)以及包数据
  • .git/refs :存放引用数据(SHA-1)
  • .git/HEAD :存放当前本地最新的应用(ref: refs/heads/master)
  • .git/index:存放暂存区内容

git理解

git是版本管理工具
git是内容寻址文件系统,其核心部分是一个简单的键值对数据库(key-value index),通过SHA-1哈希值来查找对应的原数据
git保存的是快照: (每次commit都会保存整个项目的文件数据,如果文件没有修改则保存指向原文件的指针(SHA-1值),如果修改则是修改后的文件(文件所有内容而不是差分内容))
git保存的是内容的差分 : git会在打包的时候,将所有数据整合,生成数据文件(pack-xxxx.pack)和索引文件(pack-xxx.idx),在数据文件中会以差分的形式记录有修改的文件,并且最新的是全部文件内容,之前的源文件则以差分的形式记录。
在这里插入图片描述

git原理

对象

数据对象(blob)

数据对象存储项目中的单个数据(文件)
只是单纯的记录数据内容,类似文件系统的数据块
可以存储数据,但是不知道数据是哪个文件的,只能通过SHA-1获取数据内容,记那么多40位的SHA-1值,是不科学的。

树对象(tree)

树对象存储多个文件的SHA-1值,以及子树的SHA-1值
记录数据对象的文件名,类似文件系统的目录
将数据对象与文件名对应,便于恢复文件数据,知道哪个blob对象的数据对应哪个文件了
一个项目肯定会有各种文件夹,而数据对象不能满足此要求。

提交对象(commit)

提交对象存储当前提交时间点项目的所有文件对应的树对象,以及父commit对象,提交人,提交时间,提交原因.
树对象只是记录项目的数据,无法记录数据的修改者,修改时间,以及修改原因的信息
在这里插入图片描述
总的来说,数据对象 -> 树对象 -> 提交对象

git对象存储

数据类型+空格+数据长度+空字节 -> 头信息
头信息+数据 -> SHA-1校验和
头信息+数据 -> zlib压缩 -> 磁盘内容(SHA-1头两位作目录,后38位作文件名)
查看某个对象的内容:

git cat-file -p SHA-1

git引用

引用就是指向commit的标识,也就是分支
对commit进行操作,依旧需要知道该commit对应的SHA-1值,而记录SHA-1值是非常麻烦的,所以通过一个标识(名字)来指向这个SHA-1值,就应用而生。

HEAD引用

HEAD引用是一个符号引用(symbolic reference),像linux的软链接(指向链接的文件名)
内容:ref: refs/heads/master 意思为当前本地分支为master分支

标签引用

远程引用

.git/refs/remote
其内容为某一commit的SHA-1值

包文件

git存储的是数据文件,每次修改后都会存储一份新文件(不管修改多么小),这样git仓库会越来越大,所以需要在git仓库达到一定规模的时候进行打包操作,以释放存储空间,提高查询效率等。
命令: git gc
最初git向磁盘存储对象的结构称为松散对象格式,每次修改都会添加一份完整文件到磁盘。
打包:将松散的对象打包成一个包文件(二进制文件)和一个索引文件(记录包文件的偏移量)
在打包后,修改的文件会以差分的形式存储在包文件中,最新的对象保存完整的数据,以前的源文件则以差分的形式保存。
这是基于以下考虑

  1. 一般情况下,都会查看最新的数据,保证查询效率
  2. (纯属猜测)在对文件进行还原的时候,从最新文件进行回退可以还原文件,假设初始文件记录全部数据,每次修改记录差分,则还原文件的时候,则需要从初始文件应用一系列之前的差分才能得到文件,当一个文件修改履历较长时,这无疑会进行复杂的运算。

创建分支 -> 创建一个引用,然后内容(SHA-1)指向你想切到的commit点。默认值为HEAD的值
切换分支-> 将当前分支的内容修改为目标commit点的SHA-1值。然后读取对应commit对象中树对象以及数据对象的内容,并替换当前工作空间的文件。

git gc

Counting objects: 23, done. :仓库所有的对象(commit tree blob)
Delta compression using up to 4 threads.(作增量的对象,原理不懂,可通过git verify-pack -v .git/objects/pack/pack-xxx.idx查看)
Compressing objects: 100% (11/11), done.(增量压缩对象,没整明白delte,所以这个算不明白)
Writing objects: 100% (23/23), done. 写入包文件的对象
Total 23 (delta 4), reused 23 (delta 4) reused是之前已经有的对

git push

git push 的时候会先执行git gc 然后将包文件通过网络传到远程
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 260 bytes | 260.00 KiB/s, done.
Total 3 (delta 1), reused 0 (delta 0)

git clone

git clone 的时候会在远程执行git gc 然后传包文件过来,如下
remote: Enumerating objects: 15, done.
remote: Counting objects: 100% (15/15), done.
remote: Compressing objects: 100% (11/11), done.
remote: Total 15 (delta 2), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (15/15), done.

remote: Enumerating objects -> 远程操作:枚举对象,本地和远程相差的object -> frontier边界(会找到新加commit的父commit(远程已经存在的commit))- > 确定那些是新加的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值