git:文件存储方式

2023-10-27

引言

我们知道 git 跟踪文件会经历三个阶段:工作区,暂存区和本地仓库(参考git:理解工作区,暂存区和本地仓库),在这些阶段文件如何被储存?理解 git 文件的存储方式能帮助我们掌握 git 的工作原理。


git 对象

在上述三个阶段,文件会以对象(object)的形式存储在 .git/objects 目录下,对象主要有三类:commit,tree 和 blob。假设初始目录如下:

├── .git
├── file
│   └── c.txt
├── a.txt
└── b.txt

执行 git add . 将工作区所有文件存放到暂存区,查看目录 .git/objects,看到该目录下增加了3个子目录 2e,34,63,每个子目录下有一个由字母数字命名的文件。git 根据文件内容生成 SHA-1 哈希值作为文件的校验和,创建以该校验和前2个字符为名称的子目录,并以剩下的 38 个字符为文件命名。

.git/objects
├── 2e
│   └── 65efe2a145dda7ee51d1741299f848e5bf752e
├── 34
│   └── 10062ba67c5ed59b854387a8bc0ec012479368
├── 63
│   └── d8dbd40c23542e740659a7168a0ce3138ea748
├── info
└── pack

可以使用指令 git cat-file -t %校验和前六位 查看文件类型,git cat-file -p %校验和前六位 查看文件内容。

$ git cat-file -t 2e65ef
blob
$ git cat-file -t 341006
blob
$ git cat-file -t 63d8db
blob
$ git cat-file -p 2e65ef
a
$ git cat-file -p 341006
c
$ git cat-file -p 63d8db
b

因此,当保存工作区的文件到暂存区时,git 会复制每个文件并压缩为 blob 对象,保存在 .git/objects 下。


执行 git commit 将暂存区文件上传到本地仓库,.git/objects 目录下又增加了三个子目录 0c,b1,65,分别查看其对象和内容:

# 0c2dd9 
commit
tree b15ad62733b40ee7f19be69f850fe5b575210edd
author XuanyuXiang <xuanyuxiang22@gmail.com> 1665807213 +0800
committer XuanyuXiang <xuanyuxiang22@gmail.com> 1665807213 +0800
first commit

# b15ad6 
tree
100644 blob 2e65efe2a145dda7ee51d1741299f848e5bf752e    a.txt
100644 blob 63d8dbd40c23542e740659a7168a0ce3138ea748    b.txt
040000 tree 653c8359fc980eb3a393a41a1f1cbe4e8ce458f8    file

# 653c83
tree
100644 blob 3410062ba67c5ed59b854387a8bc0ec012479368    c.txt

此时生成了一个 commit 对象,两个 tree 对象。commit 存放 b15ad6 的地址和一些用户信息;b15ad6 是一个 tree,存放其下的 blob 地址和 653c83 的地址;653c83 是一个 tree,存放其下的 blob 地址。分析得出,git commit 生成 commit 对象和 tree 对象,commit 指向整个项目目录,tree 用于构建整个项目的目录结构,同时暂存区的 blob 对象也会移入本地仓库,暂存区清空。其关系如下:

0c2dd9: commit
└── b15ad6: tree
    ├── 653c83: tree
    │   └── 341006: blob
    ├── 2e65ef: blob
    └── 63d8db: blob

现在我们修改 a.txt 的内容并提交一个新的 commit:

echo "helloGit" > a.txt
git add .
git commit -m "modify a.txt"

.git/objects 目录下又增加了3个子目录,7c,46,74,分别查看其类型和内容:

# 466622
commit
tree 7c0ef1dab56cd8d2ac5c3cda20ddadb4765e8311
parent 0c2dd90ef3827e608b3ea9fba424d1ff68353216
author XuanyuXiang <xuanyuxiang22@gmail.com> 1665809170 +0800
committer XuanyuXiang <xuanyuxiang22@gmail.com> 1665809170 +0800
new branch modified a.txt

# 7c0ef1
tree
100644 blob 7423c81faa8c815b6e8a1742fcc321d457cfaab0    a.txt
100644 blob 63d8dbd40c23542e740659a7168a0ce3138ea748    b.txt
040000 tree 653c8359fc980eb3a393a41a1f1cbe4e8ce458f8    file

# 7423c8
blob
helloGit

此时的 commit 多了一个 parent 对象,它指向上一个 commit;请注意 7423c8 虽然对应 a.txt,但由于修改了内容,7423c8 是一个全新的 blob 对象(此时 2e65ef 仍然存在)。本地仓库保存的 commit,tree,blob 是永远不会被删除的。新的指向关系如下:

0c2dd9: commit —————————————————— 466622: commit
└── b15ad6: tree                  └── 7c0ef1: tree
    ├── 653c83: tree                  ├── 653c83: tree
    │   └── 341006: blob              │   └── 341006: blob
    ├── 2e65ef: blob                  ├── 7423c8: blob
    └── 63d8db: blob                  └── 63d8db: blob

git 指针

HEAD 可以理解为指向当前分支的指针,查看 .git/HEAD 内容,确实指向当前的 master 分支:

$ cat .git/HEAD
ref: refs/heads/master

分支可以理解为指向当前 commit 的指针,查看 .git/refs/heads/master,它指向 466622,这就是上面的 commit 对象。分支指针通过指向不同 commit 实现版本的切换,HEAD 通过指向不同分支实现分支切换。

参考

Git内部存储原理

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

git:文件存储方式 的相关文章

随机推荐

  • 测试网络连通性

    测试网络连通性的方式 ssh v p 端口 root IP curl ip 端口 nc v IP 端口
  • SQL Server 数据库之变量

    变量 1 变量概述 1 1 常规标识符 1 2 分隔标识符 2 局部变量 2 1 局部变量声明 2 2 局部变量赋值 2 3 变量显示 3 全局变量 3 1 全局变量注意事项 3 2 常用的全局变量 4 注释符 5 运算符 5 1 算术运算
  • 【CV】从 YOLO 到 YOLOv8:追踪目标检测算法的演变

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • 使用Flutter和Arduino控制设备

    硬件 配置Arduino IDE Arduino服务器 首先 让TCP服务器运行并测试其是否正常运行 创建一个WiFi服务器对象 现在让我们填写setup 函数 将串行连接配置为115 200 bps的速度 等待一秒钟以确保串行连接已初始化
  • JMeter压力测试实例操作

    1 脚本录制 脚本录制 JMeter启用WEB代理 浏览器把代理上网设置为JMeter所在的IP地址 自己电脑就是127 0 0 1代理端口默认8080 至于浏览器修改代理上网服务器 不做截图 Jmeter 运行在目录 apache jme
  • Qt 的几个常用部件 -- QFrame

    文章目录 基本信息 公共类型 可用来设置的 详细描述 可以处理的事件 基本信息 头文件 include
  • 微信小程序——订阅消息与微信公众号模板消息

    订阅消息 一次性订阅消息 某个按钮 并且只能是用户自己就手动点击的 操作调起来这个允许授权弹窗 允许通知之后也只能发送一次消息 即便点上 总是保持一上选择 不再询问 也只是在下次点击同一个按钮时默认允许发送消息 不是可以一直发送消息的 使用
  • python文件处理方式

    python文件处理方式 file open D pythonText txt r encoding UTF 8 print file lt io TextIOWrapper name D pythonText txt mode r enc
  • IntelliJ IDEA (Ultimate Edition)2021.1配置javaFX8(Mac Pro) 踩坑

    该文写于2022 1 22日 应该算是比较新的坑吧 仅供参考 转发请注明出处 该版本内置了javaFX模块 创建项目可以在左侧工具栏看到JavaFX选项 创建项目后 intelliJ自动创建的项目结构如下图 打开Main文件 发现一大堆红色
  • iOS: HTTPS 与自签名证书

    不是每个公司都会以数百美金一年的代价向CA购买SSL证书 在企业应用中 付费的SSL证书经常被自签名证书所替代 当然 对于自签名证书iOS是没有能力验证的 Safari遇到这种无法验证的自签名证书的唯一处理方法 就是将问题扔给用户 让用户决
  • zSetOperations=redisTemplate.opsForZSet();redis的Zset数据类型方法大全(zSetOperations常用方法详细)

    zSetOperations redisTemplate opsForZSet 以下是 zSetOperations 接口中定义的所有方法及其详细说明 void add K key V value double score 将一个成员添加到
  • JDBC(The end)—— 数据库连接池示例 (与线程池梦幻联动)

    写在之前 不管以后对于那种类型的池 都需要List接口利用多态的写法来对一系列集合框架类进行实例化对象 以此该对象调用add方法 来装多个此种类型的实例化对象 数据库连接池的设计思路比线程池简单易懂 以下是示例 和之前线程池的设计思想相同之
  • python怎么搭建免费代理IP池

    搭建免费代理 IP 池需要经过以下步骤 1 抓取免费代理 IP 可以通过爬虫抓取免费的代理 IP 例如可以使用 requests 和 BeautifulSoup 库实现 需要注意的是 免费代理 IP 的可用性通常比较低 需要考虑测试代理 I
  • 计算机网络学习笔记--基带(base)信号

    基带 base 保持数据波的原样进行传输称为基带传输或者基带数字信号传输 宽带 broad 在数据通信领域则指数据传输速率超过1Mps的传输系统 宽带信号则是将基带信号进行调制后形成的频分复用模拟信号 基带信号进行调制后 其频谱搬移到较高的
  • Linux更改SSH端口,并解决SSHD服务重启失败的问题

    环境 Linux Centos 7 1 进入sshd配置文件 vi etc ssh sshd config 2 找到 Port 22 这行 删掉注释符 将端口改为 想要变成的端口号 如 2022 3 重启sshd服务 systemctl r
  • 微信小程序后台销毁时间 演变和总结(热启动时间限制)

    小程序启动 这样 小程序启动可以分为两种情况 一种是冷启动 一种是热启动 冷启动 如果用户首次打开 或小程序销毁后被用户再次打开 此时小程序需要重新加载启动 即冷启动 热启动 如果用户已经打开过某小程序 然后在一定时间内再次打开该小程序 此
  • Java实现微信登录

    Java实现微信登录 代码实现微信授权 简单来说 微信授权分为四步 1 授权登录接口 生成一个二维码在页面中 2 用户点击授权成功后自动获取code 3 浏览器自动利用code访问回调接口 4 在回调接口中利用code登录 appId ap
  • Android嵌入式系统程序开发

    Android嵌入式系统程序开发 基本信息 作者 胡文 宁世勇 李明俊 金雪松 丛书名 单片机与嵌入式丛书 出版社 机械工业出版社 ISBN 9787111411697 上架时间 2013 4 2 出版日期 2013 年4月 开本 16开
  • oracle rac io,ORACLE RAC 之I/O分离--hangcheck-timer模块配置

    ORACLE RAC 之I O分离 hangcheck timer模块配置 此文档摘自METALINK 726833 1 所适用的ORACLE版本为 Oracle Server Enterprise Edition Version 9 2
  • git:文件存储方式

    引言 我们知道 git 跟踪文件会经历三个阶段 工作区 暂存区和本地仓库 参考git 理解工作区 暂存区和本地仓库 在这些阶段文件如何被储存 理解 git 文件的存储方式能帮助我们掌握 git 的工作原理 git 对象 在上述三个阶段 文件