一篇文章看懂git的内部存储结构

Git是一个开源的分布式版本控制系统,目前大多数团队都采用Git作为团队内部的版本控制系统,并且在DevOps的整体流程中,版本控制是其中重要的一环,在“基础设施即代码”的理念下,不止是系统源代码,系统配置纳入版本管理,数据和环境配置也要纳入版本管理,可以说,版本管理使得研发流程可复用、标准化、自动化,进而提高了研发效率。

大多数人在使用git时,大多数都是使用IDE封装好的GUI界面操作,少量使用者也是git add,git commit,git pull几个常用的命令。对于git的用户来说,这些都足够了。如果你是一个DevOps开发者或是想成为Git的深度用户,知道这些是远远不够的。下面就让我们了解一下Git背后的逻辑。

第一、Git的三个区+一个远程仓库

这个图好多人都应该见过。里面也是一些经常使用的命令。主要包含几个部分:

Remote:远程仓库,像github就是一个远程仓库。

Repository:本地仓库,通过git clone将远程仓库的代码下载到本地。代码库的元数据信息在根目录下的.git目录下。

Workspace:工作空间,就是我们写代码的目录。

Index:暂存区,指的是.git目录下的index文件。

在平时写完代码后执行git add 就是将变更的内容从工作空间提交到暂存区,git commit就是将暂存区的内容提交到本地代码库里,git push 就是将本地代码库的变更提交到远程仓库,这时其他人就能通过pull 将你的变更下载到工作空间。

第二、git的内部存储结构

新建一个gittest目录,然后执行git init就会初始化一个本地仓库。打开.git目录文件列表如下:

hooks:是存储git钩子的目录,钩子是在特定事件发生时触发的脚本。比如:提交之前,提交之后。

info:是存储git信息的目录,比如排除特定后缀的文件.

objects:是存储git各种对象及内容的对象库,包含正常的和压缩后的。

refs:是存储git各种引用的目录,包含分支、远程分支和标签。

config:是代码库级别的配置文件。

HEAD:是代码库当前指向的分支,这里为master。

一、新建README.md文件

新建README.md文件,并输入内容“This is test file!”

git add README.md 将工作空间的变更提交到暂存区。

.git/index文件会被修改,通过git ls-files --stage 查看暂存区的内容,可以看到README.md文件有修改,通过git cat-file -p SHA-1查看文件内容。

同时.git/objects下也会有新的对象,如下:

这个对象就是刚才add到暂存区的对象,在.git/objects目录下看到一个文件。这便是Git存储数据内容的方式--为每份内容生成一个文件,取该内容与头信息的SHA-1校验和,创建以该校验和前两个字符为名称得子目录,并以校验和剩下38个字符为文件命名。这里并没有显示真实的文件名。

通过git cat-file -t SHA-1查看对象的类型。blob代表文件。

二、创建一个目录web,并添加一个web.txt文件

执行git add web/ 添加到暂存区。

查看暂存区内容,变成了2条记录,存储方式和上面文件一样。

可以看出,这里只有文件内容生成的文件,没有为目录生成文件。

在.git/objects下面也创建了相应的目录和文件。

三、提交内容

到目前为止,暂存区的内容有README.md和web/web.txt文件。下面通过git commit 将暂存区的内容提交到本地仓库。

使用git log 查看本次提交信息,使用git cat-file -p查看变更内容,当类型为tree时表示文件夹,会显示该文件夹下的文件或目录列表,当类型为blob时为文件,会显示该文件的内容。

因此本次commit的存储模型为:

此时再查看.git/objects目录下,有增加了几个目录。其中:

8d:提交的commit对象

58和ff:提交的commit对应的tree对象和web目录的tree对象。

a1和b3:提交的README.md文件和web/web.txt文件对应的数据对象。

可以看出,当我们执行git add 和git commit 命令时,Git做的工作是将被改写的文件保存为数据对象、更新暂存区,记录树对象,最后创建一个指明了顶层树对象和父提交的提交对象。这三种Git对象(数据对象-blob、树对象-tree、提交对象-commit)最后均以单独文件的形式保存在.git/objects目录下。

四、新建分支test

上面提到分支、远程分支和标签都会存储在.git/refs下。

heads包含分支,tags包含标签。每个引用文件里都会指向一个commit,如基于master分支新建的test分支 git branch test:

使用git checkout test切换到test分支,此时HEAD的内容为refs/heads/test,表示当前分支为test.

在test分支下修改文件内容:

git status查看工作空间状态,有两个修改过的文件。

git add .将变更的文件添加到暂存区,查看暂存区内容发现:

README.md的校验和从之前的a177f89--->7a51843

web/web.txt的校验和从之前的b31494b--->f5ebb2c

查看文件内容也是最新修改的内容。

.git/objects目录下也多了2个新的目录

git commit 将暂存区的内容提交到本地仓库。和上面一样,此时也会创建提交对象,树对象,通过查看不同的对象,最后都能查看到具体的数据对象的最新内容。

同时在.git/objects下也会创建提交对象c7,树对象cf和树对象a3

五、分支合并冲突

在master分支修改web/web.txt,将内容改为“this is a old web.txt”,以便产生冲突。

git add 添加到暂存区,查看文件内为新修改的内容。

git commit添加到本地仓库,同时生成提交对象,树对象。

执行git merge test进行分支合并,web/web.txt出现冲突。

分支合并后,master分支的commit由之前的  8da82ba变为c75be2f。

暂存区中的README.md的校验和也由master分支的 a177f89变成7a51843。

而web/web.txt变成了3个文件,b3是master当前commit的父commit的校验和,18是master最新提交的校验和,f5是test分支上的校验和。

解决冲突,两行内容都保留,结果如下:

git add 添加到暂存区,查看暂存区内容,README.md是test分支上的,web/web.txt是解决完冲突新生成的校验和。

也就是说,分支合并会修改当前分支的commit信息以及暂存区的内容,当解决完冲突后,将冲突文件git add 添加到暂存区,然后git commit 将合并后的内容提交到本地仓库。

也就是说,合并完冲突后,只有将更新后的内容commit,在生成的提交对象上才能找到新加的内容。

这里回答下遇到的一个问题:

问题:我当前分支是test分支,当从master分支合并过来后冲突了,我解决完冲突,只提交了这个文件,其他文件不用提,因为其他文件的内容已经在master分支上了,当我从test分支再合并回master分支后,也应该没有问题。

解释:根据上面的分析,每个commit都是一个提交对象,这个提交对象关联一个树对象,树对象会包含最新的数据对象。当从master分支合并后,master的commit提交对象包含的树对象和数据对象,会作为新的文件内容存放到test分支的暂存区,此时有2种选择:

①,当在test分支commit时,这次生成的提交对象才会包含master过来的文件内容。

②,如果此时放弃提交(手动checkout当前分支最新的),那么当前commit提交对象不包含master的文件内容,当test分支合并回master时,也会将test分支的文件内容存放到master分支的暂存区,当push到远程仓库时,也就是test分支的数据对象的内容,因此其他人拿到的文件内容就会丢失。

往期文章

1、云原生时代下的CICD应该关注什么

2、如何解决git版本冲突,才不会酿成大错

3、一篇文章学会使用gitk,排查git问题就靠它了

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容

  • 一、Git是什么? 是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常 大的项目版本管理。 Git ...
    名字谁不会取阅读 1,039评论 0 0
  • GIT分布式版本控制系统最佳实践 这篇文章来自于老男孩教育高级架构师班12期的徐亮偉同学。 首先感谢老男孩架构师班...
    meng_philip123阅读 3,408评论 4 36
  • 来源:Git由浅入深之操作与指令作者:惊鸿三世(转载已获得原作者许可,如需转载请与原作者联系) 本篇正式开始介绍G...
    极乐君阅读 1,633评论 9 67
  • 一、基本概念: 注:对于git的分布式概念及其优点,不重复说明,自己百度或谷歌。本文中涉及到指令前面有$的,在cm...
    大厂offer阅读 1,423评论 0 3
  • 思想:上午拾掇整齐参加了升旗仪式,欣欣向荣的感觉;每次参加升旗仪式都觉得被鼓舞,满满的正能量~ 今天仓库捣货,兄弟...
    张建鑫_8934阅读 302评论 0 0