深入Git-中篇

简介: 前言上篇文章深入Git-上篇我们介绍了Git的目录结构,对于仓库的核心实现objects我们选择先跳过了。本篇文章就主要讲讲objects,通过本篇文章可以了解Git的仓库存储,其版本的实现逻辑等。

深入Git-中篇

「这是我参与2022首次更文挑战的第11天,活动详情查看:2022首次更文挑战

前言

上篇文章深入Git-上篇我们介绍了Git的目录结构,对于仓库的核心实现objects我们选择先跳过了。本篇文章就主要讲讲objects,通过本篇文章可以了解Git的仓库存储,其版本的实现逻辑等。


Git的三个分区


在开始学习前,我们先简单了解下Git的三个分区。

49.png


  • 工作区


顾名思义我们进行编辑操作的就是工作区的内容


  • 暂存区(索引)


可以理解为暂存着下一次commit的版本仓库


  • 版本库


存放所有版本内容的仓库,不同版本的文件及内容都可以在其中找到


objects结构

objects
├── info
└── pack
复制代码


初始化时objects下面仅包含两个目录,info和pack,其中pack将存储ojects下其它文件的打包压缩后的结果。


仓库文件类型


刚刚初始化的仓库objects下面是没有任何东西的,下面我们将通过添加文件等操作,为其添加不同类型的文件。


在工作区添加文件及内容


echo 'hello world' > a.txt
复制代码

blob

此刻,我们的objects还是为空的,我们将其添加到暂存区


git add a.txt
复制代码


我们再通过tree打印下objects目录,可以发现多了文件夹3b,下面有文件18e512dba79e4c8300dd08aeb37f8e728b8dad。文件名和我们平常使用的commitId类似。


├── 3b
│   └── 18e512dba79e4c8300dd08aeb37f8e728b8dad
├── info
└── pack
复制代码


实际上文件名是根据文件内容通过SHA1哈希算法生成的,完整值为3b18e512dba79e4c8300dd08aeb37f8e728b8dad,存储在objects的时候会将前两位字符提取用于分桶存储,而文件内容则是个二进制文件。

00000000: 7801  4bca  c94f  5230
00000008: 3462  c848  cdc9  c957
00000010: 28cf  2fca  49e1  0200
00000018: 4411  0689
复制代码


为了更加清楚地展示其内容,我们再介绍一个命令

git cat-file -t <fileId> # 文件类型
git cat-file -p <fileId> # 文件内容
复制代码


我们来看看刚才在objects下生成的文件

git cat-file -t 3b18e512dba79e4c8300dd08aeb37f8e728b8dad # blob
git cat-file -p 3b18e512dba79e4c8300dd08aeb37f8e728b8dad # hello world
复制代码

41.png


tree

接着我们将文件添加到版本库中


git commit -m firstcommit
复制代码


可以发现objects下面生成了两个文件

5ce458a111f86b77eb9399931b0391d27f75cfacebaa691b5554f29ac9d4f37811a1da6f24d376a1

.
├── 3b
│   └── 18e512dba79e4c8300dd08aeb37f8e728b8dad
├── 5c
│   └── e458a111f86b77eb9399931b0391d27f75cfac
├── eb
│   └── aa691b5554f29ac9d4f37811a1da6f24d376a1
├── info
└── pack
复制代码


我们先看看ebaa691b5554f29ac9d4f37811a1da6f24d376a1的内容

git cat-file -t ebaa691 # tree
复制代码

因为SHA1可以通过前7位确定寻找到唯一值,所以我们平常工作中都可以使用简短ID即前7位


区别于前面的blob类型,这边新出现一个tree类型(实际其内容仍然是通过二进制保存)

git cat-file -p ebaa691 
# 100644 blob 3b18e512dba79e4c8300dd08aeb37f8e728b8dad  a.txt
复制代码


tree文件实际对应当前commit操作时的暂存区快照。因为我们只添加了一个文件,所以只会输出一行内容,也就是a.txt相关信息。从左至右依次为文件权限-文件类型-文件哈希-文件名

值得注意的是tree文件保存了文件的文件名而blob仅仅保存了文件内容。这样做的好处是,在通常情况下文件的内容是比目录结构大得多的情况下。当文件名修改时,我们仅仅需要生成新的tree文件,而不用因为文件名的修改而更新blob。


42.png

commit

我们接着看另外一个文件


git cat-file -t 5ce458a # commit
复制代码


出现新的文件类型commit

git cat-file -p 5ce458a
复制代码


其文件内容包括刚才生成的treeID,提交用户相关信息及提交信息。因为我们这是第一次提交,所以不会有parentId。在之后的commit文件中则会在parentId中保存上次的commitId。

tree ebaa691b5554f29ac9d4f37811a1da6f24d376a1
author xxx <xxx@qq.com> 1643509265 +0800
committer xxx <xxx@qq.com> 1643509265 +0800
firstcommit
复制代码


43.png

小结

通过上面的实践,我们认识了Git版本库中三种文件类型

类型 存储信息
blob 文件内容
tree 目录快照(包括文件权限,文件类型,文件ID,文件名)
commit 版本信息(包括提交用户信息,treeID,parentID,提交信息)

以上文件的相同点在于



  1. 存储在objects,通过前两位哈希值进行分桶

  2. 文件实际类型都为blob文件

  3. 文件名都是通过SHA1哈希得到

版本控制


前面我们分析了在版本库中不同文件类型及其保存的内容。在其基础上,我们可以分析出Git版本控制的大致流程。我们通过实例来分析


  1. 在工作区添加内容

echo 'a' > a.txt
echo 'b' > b.txt
复制代码

44.png

  1. 将工作区内容添加到暂存区,在版本库中生成blob文件
git add .
复制代码

45.png

  1. 对暂存区生成快照tree文件
git commit -m first
复制代码

46.png

  1. 生成第一个版本commit文件,其文件名则是我们平常使用的commitID

47.png


  1. 我们更新a.txt
echo a2 > a.txt
复制代码

48.png


  1. 将更新同步到暂存区
git add a.txt
复制代码

49.png


  1. 生成新的版本
git commit -m second
复制代码

50.png

抛出几个思考


  1. 会不会有重复的commitID


在我们上面分析版本实现的逻辑上,实际可以发现版本库实际实现了一颗哈希树。在哈希树中,其哈希值通过子节点进行哈希算法得到且不会重复。


  1. 我们能否篡改某个commit的内容而不被发现?


实际Git是提供了命令让我们回退到中途某个版本进行修改的,但是我们修改内容后没法不被发现。同样因为哈希树的实现,当我们修改某个commit版本的时候,其comnitId肯定是会更改的,此时前后面对应的commit文件中保存的parentId会改变,所以此时参与哈希计算的内容(parentId)实际会改变导致后面版本的commitID都会跟着改变。


  1. 对于修改内容,版本中是保存增量还是全量数据?


通过上文的分析,实际已经可以知道答案。Git中保存了每次更新后的全量文件,这也是为什么我们切换版本或者切换分支会非常快的原因,省去了遍历不同版本应用patch的操作。当然每次保存更新后的全量文件会使我们的仓库变得非常大,而Git相应的会对仓库下的文件进行打包压缩来减小仓库体积,打包后的结果放在前文所说的pack文件夹下面。


结语


本篇文章主要分析了Git仓库的存储机制,其是如何保存不同版本的内容


参考



相关文章
|
Web App开发 存储 开发工具
Git探秘:深入探索(2/2)
## 概念 通过上篇文章,初步接触Git的朋友应该已经对Git有所了解了,既然你已经打开了这篇文章,说明你对深入了解Git有强烈的欲望,那就跟着我一起先来深入了解一下Git相关的概念。 ### 工作区(Working Directory) 就是你在电脑里能看到的目录,比如上文中的 **reading-ist** 文件夹就是一个工作区 ![](https://img.alic
1734 0
|
前端开发 开发工具 git
Git探秘:实用主义(1/2)
## 简介 Git是一种分布式版本控制系统,它可以不受网络连接的限制,加上其它众多优点,目前已经成为业界做项目版本管理时的首选。 Tips:非开发人员也可以用Git来做自己的文档版本管理 2013年,淘宝前端团队开始全面采用Git来做项目管理,我也是那个时候开始接触和使用Git,到目前刚好3年时间。Git的api很多,但其实平时项目中90%的需求都只需要用到几个基本的功能
2184 0
|
9月前
|
存储 Linux 开发工具
你再不学Git就来不及了!!!
版本控制是一种记录一个或若干文件内容变化,以便将来查阅特定版本修订情况的系统。除了项目源代码,你可以对任何类型的文件进行版本控制。
94 1
|
机器学习/深度学习 存储 开发工具
git奇技淫巧
git奇技淫巧
97 0
|
存储 前端开发 网络安全
Git 的奇技淫巧
Git 是一个 “分布式版本管理工具”,简单的理解版本管理工具:大家在写东西的时候都用过 “回撤” 这个功能,但是回撤只能回撤几步,假如想要找回我三天之前的修改,光用 “回撤” 是找不回来的。而 “版本管理工具” 能记录每次的修改,只要提交到版本仓库,你就可以找到之前任何时刻的状态(文本状态)。
150 0
|
6月前
|
存储 缓存 开发工具
【GIT 第一篇章】认识一下GIT
Git是一款分布式版本控制系统,以高效敏捷著称,适用于从小到大的各类项目管理。其核心特性包括分布式的仓库设计,让每位开发者都能拥有完整的项目历史记录;版本控制功能追踪文件变化并保存每次提交的快照;以及强大的分支管理,支持实验性开发而不干扰主分支。Git的工作流程涉及初始化仓库、暂存更改、提交版本及查看历史等步骤。Git具备快速高效的数据处理能力、保证版本完整性的哈希机制、多协议支持和缓存机制,广泛应用于软件开发、项目管理和学术研究领域。与集中式版本控制系统SVN相比,Git在系统架构、数据存储、分支管理、性能效率和安全性等方面表现出更强的灵活性和高效性,尤其适合分布式团队和大规模项目。
63 0
|
5月前
|
SQL 缓存 测试技术
代码管理工具之GIT:重新温习一下
代码管理工具之GIT:重新温习一下
|
开发工具 git 索引
Git 系列之四:Git 进阶功能-转载
Git 系列之四:Git 进阶功能 【TIP】在我们的《Windows 下 Git 配置与使用指南》 中,有介绍大家使用 $ git go 命令。其实,这并非 Git 的原生命令,它是我们自定义的一个 alias(别名),由 $git add、$git commit、$git push 和 $git pull 四个命令组合而成。
855 0
|
开发工具 git
git填坑笔记
Counting objects: 3, done.Writing objects: 100% (3/3), 203 bytes | 0 bytes/s, done.Total 3 (delta 0), reused 0 (delta 0)remote: error: insufficient pe...
737 0
|
开发工具 git
哎呦我去,Git 竟然可以这么用?!!
用好 Git 很难: 很容易就犯错了,然后想自己弥补犯下的错,简直太难了。
190 0

热门文章

最新文章

相关实验场景

更多