网易首页 > 网易号 > 正文 申请入驻

Git内部原理揭秘!从文件更改到代码储存,Git究竟是怎么实现的

0
分享至

   新智元推荐 来源:腾讯技术工程 作者:lzaneli 【新智元导读】本文以一个具体实例结合动图介绍了Git的内部原理,包括Git是如何储存我们的代码和变更历史的、在更改一个文件时,Git内部是怎么变化的、Git这样实现有什么好处等等。 戳右边链接上 了解更多!

  前言

  近几年技术发展十分迅猛,让部分同学养成了一种学习知识停留在表面,只会调用一些指令的习惯。我们时常有一种“我会用这个技术、这个框架”的错觉,等到真正遇到问题,才发现事情没有那么简单。

  而Git也是一个大部分人都知道如何去使用它,知道有哪些命令,却只有少部分人知道具体原理的东西。了解一些底层的东西,可以更好的帮你理清思路,知道你真正在操作什么,不会迷失在Git大量的指令和参数上面。

  Git是怎么储存信息的

  这里会用一个简单的例子让大家直观感受一下git是怎么储存信息的。首先我们先创建两个文件:

  $ git init $ echo '111' > a.txt $ echo '222' > b.txt $ git add *.txt

  Git会将整个数据库储存在.git/目录下,如果你此时去查看.git/objects目录,你会发现仓库里面多了两个object。

  $ tree .git/objects .git/objects ├── 58 │ └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c ├── c2 │ └── 00906efd24ec5e783bee7f23b5d7c941b0c12c ├── info └── pack

  好奇的我们来看一下里面存的是什么东西:

  $ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c xKOR0a044K%

  怎么是一串乱码?这是因为Git将信息压缩成二进制文件。但是不用担心,因为Git也提供了一个能够帮助你探索它的api git cat-file [-t] [-p], -t可以查看object的类型,-p可以查看object储存的具体内容。

  $ git cat-file -t 58c9 blob $ git cat-file -p 58c9 111

  可以发现这个object是一个blob类型的节点,他的内容是111,也就是说这个object储存着a.txt文件的内容。

  这里我们遇到第一种Git object,blob类型,它只储存的是一个文件的内容,不包括文件名等其他信息。然后将这些信息经过SHA1哈希算法得到对应的哈希值
58c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c,作为这个object在Git仓库中的唯一身份证。

  也就是说,我们此时的Git仓库是这样子的:

  我们继续探索,创建一个commit。

  $ git commit -am '[+] init' $ tree .git/objects .git/objects ├── 0c │ └── 96bfc59d0f02317d002ebbf8318f46c7e47ab2 ├── 4c │ └── aaa1a9ae0b274fba9e3675f9ef071616e5b209 ...

  我们会发现当我们commit完成之后,Git仓库里面多出来两个object。同样使用cat-file命令,我们看看它们分别是什么类型以及具体的内容是什么。

  $ git cat-file -t 4caaa1 tree $ git cat-file -p 4caaa1 100644 blob 58c9bdf9d017fcd178dc8c0... a.txt 100644 blob c200906efd24ec5e783bee7... b.txt

  这里我们遇到了第二种Git object类型——tree,它将当前的目录结构打了一个快照。从它储存的内容来看可以发现它储存了一个目录结构(类似于文件夹),以及每一个文件(或者子文件夹)的权限、类型、对应的身份证(SHA1值)、以及文件名。

  此时的Git仓库是这样的:

  $ git cat-file -t 0c96bf commit $ git cat-file -p 0c96bf tree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209 author lzane 李泽帆 1573302343 +0800 committer lzane 李泽帆 1573302343 +0800 [+] init

  接着我们发现了第三种Git object类型——commit,它储存的是一个提交的信息,包括对应目录结构的快照tree的哈希值,上一个提交的哈希值(这里由于是第一个提交,所以没有父节点。在一个merge提交中还会出现多个父节点),提交的作者以及提交的具体时间,最后是该提交的信息。

  此时我们去看Git仓库是这样的:

  到这里我们就知道Git是怎么储存一个提交的信息的了,那有同学就会问,我们平常接触的分支信息储存在哪里呢?

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

  在Git仓库里面,HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应com。mit的SHA1值。

  其实还有第四种Git object,类型是tag,在添加含附注的tag(git tag -a)的时候会新建,这里不详细介绍,有兴趣的朋友按照上文中的方法可以深入探究。

  至此我们知道了Git是什么储存一个文件的内容、目录结构、commit信息和分支的。其本质上是一个key-value的数据库加上默克尔树形成的有向无环图(DAG)。这里可以蹭一下区块链的热度,区块链的数据结构也使用了默克尔树。

  Git的三个分区

  接下来我们来看一下Git的三个分区(工作目录、Index 索引区域、Git仓库),以及Git变更记录是怎么形成的。了解这三个分区和Git链的内部原理之后可以对Git的众多指令有一个“可视化”的理解,不会再经常搞混。

  接着上面的例子,目前的仓库状态如下:

  这里有三个区域,所储存的信息分别是:

  工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。

  索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次commit被提交到Git仓库。

  Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。

  我们来看一下更新一个文件的内容这个过程会发生什么事。

运行echo "333" > a.txt将a.txt的内容从111修改成333,此时如上图可以看到,此时索引区域和git仓库没有任何变化。

运行git add a.txt将a.txt加入到索引区域,此时如上图所示,git在仓库里面新建了一个blob object,储存了新的文件内容。并且更新了索引将a.txt指向了新建的blob object。

  运行git commit -m 'update'提交这次修改。如上图所示

  Git首先根据当前的索引生产一个tree object,充当新提交的一个快照。

  创建一个新的commit object,将这次commit的信息储存起来,并且parent指向上一个commit,组成一条链记录变更历史。

  将master分支的指针移到新的commit结点。

  至此我们知道了Git的三个分区分别是什么以及他们的作用,以及历史链是怎么被建立起来的。基本上Git的大部分指令就是在操作这三个分区以及这条链。可以尝试的思考一下git的各种命令,试一下你能不能够在上图将它们“可视化”出来,这个很重要,建议尝试一下。
一些有趣的问题

  有兴趣的同学可以继续阅读,这部分不是文章的主要内容。

  问题1:为什么要把文件的权限和文件名储存在tree object里面而不是blob object呢?

  想象一下修改一个文件的命名。如果将文件名保存在blob里面,那么Git只能多复制一份原始内容形成一个新的blob object。而Git的实现方法只需要创建一个新的tree object将对应的文件名更改成新的即可,原本的blob object可以复用,节约了空间。

  问题2:每次commit,Git储存的是全新的文件快照还是储存文件的变更部分?

  由上面的例子我们可以看到,Git储存的是全新的文件快照,而不是文件的变更记录。也就是说,就算你只是在文件中添加一行,Git也会新建一个全新的blob object。那这样子是不是很浪费空间呢?

  这其实是Git在空间和时间上的一个取舍,思考一下你要checkout一个commit,或对比两个commit之间的差异。如果Git储存的是问卷的变更部分,那么为了拿到一个commit的内容,Git都只能从第一个commit开始,然后一直计算变更,直到目标commit,这会花费很长时间。而相反,Git采用的储存全新文件快照的方法能使这个操作变得很快,直接从快照里面拿取内容就行了。

  当然,在涉及网络传输或者Git仓库真的体积很大的时候,Git会有垃圾回收机制gc,不仅会清除无用的object,还会把已有的相似object打包压缩。

  问题3:Git怎么保证历史记录不可篡改?

  通过SHA1哈希算法和哈希树来保证。假设你偷偷修改了历史变更记录上一个文件的内容,那么这个问卷的blob object的SHA1哈希值就变了,与之相关的tree object的SHA1也需要改变,commit的SHA1也要变,这个commit之后的所有commit SHA1值也要跟着改变。又由于Git是分布式系统,即所有人都有一份完整历史的Git仓库,所以所有人都能很轻松的发现存在问题。

  希望大家读完有所收获,下一篇文章会写一些我日常工作中觉得比较实用的Git技巧、经常被问到的问题、以及发生一些事故时的处理方法。

  参考资料:

  Scott Chacon, Ben Straub - Pro Git-Apress (2014) 免费,有兴趣继续深入的同学推荐阅读这本书 Jon Loeliger, Matthew McCullough - Version Control with Git, 2nd Edition - O'Reilly Media (2012) 作为上面那本书的补充

  B站视频链接: https://www.bilibili.com/video/av77252063 PPT 链接: https://www.lzane.com/slide/git-under-the-hood

  本文经授权转载自微信公众号“腾讯技术工程”

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
妈妈被入室歹徒折磨近2小时不敢出声,只为保全楼上熟睡的女儿

妈妈被入室歹徒折磨近2小时不敢出声,只为保全楼上熟睡的女儿

领略非凡
2026-07-10 11:48:29
豪车逆行撞到我军车,对方猖狂扬言随便告,首长下车后他傻眼了

豪车逆行撞到我军车,对方猖狂扬言随便告,首长下车后他傻眼了

兰姐说故事
2025-05-03 10:00:13
外交官已全部撤离,立陶宛新总理立军令状,就等中方给个改过机会

外交官已全部撤离,立陶宛新总理立军令状,就等中方给个改过机会

小影的娱乐
2026-07-11 14:54:16
连战回忆录爆出惊人观点:要统一先正视“中华民国”?大陆怎么接

连战回忆录爆出惊人观点:要统一先正视“中华民国”?大陆怎么接

老腘的世界视角
2026-07-09 19:20:47
2026下半年,凭借实力逆袭的三大生肖,后劲十足,赚得家产万贯

2026下半年,凭借实力逆袭的三大生肖,后劲十足,赚得家产万贯

毅谈生肖
2026-07-12 12:21:02
高温预警!梧桐山一游客登山突发身体不适,经抢救无效离世

高温预警!梧桐山一游客登山突发身体不适,经抢救无效离世

南方都市报
2026-07-11 15:14:12
“要是在晚上,更诡异”,上海一景区有48个人形玻璃雕像,游客觉得有点吓人;景区:体现的是人与自然的对话

“要是在晚上,更诡异”,上海一景区有48个人形玻璃雕像,游客觉得有点吓人;景区:体现的是人与自然的对话

大风新闻
2026-07-09 19:43:04
17时0分,中方下发一纸禁令,同步封住30国后路,美日都被锁喉了

17时0分,中方下发一纸禁令,同步封住30国后路,美日都被锁喉了

纪中百大事
2026-07-12 09:44:28
恩博洛跳水因“身份错判”被VAR介入,阿尔米隆也曾遇到相似情况

恩博洛跳水因“身份错判”被VAR介入,阿尔米隆也曾遇到相似情况

懂球帝
2026-07-12 10:54:05
堪比姑父当年!朝鲜召开专题大会通报人民军总政治局前组织副局长朴喜哲特大腐败案详情

堪比姑父当年!朝鲜召开专题大会通报人民军总政治局前组织副局长朴喜哲特大腐败案详情

IN朝鲜
2026-07-11 14:53:51
浏览量破亿哈兰德本尊回复!爆火的“哈兰葱”竟是重庆小伙花一小时精挑的蒜苗

浏览量破亿哈兰德本尊回复!爆火的“哈兰葱”竟是重庆小伙花一小时精挑的蒜苗

上游新闻
2026-07-11 14:59:06
江苏多地发布倡议:非必要不出门,在家宅一天,尽量别点外卖!

江苏多地发布倡议:非必要不出门,在家宅一天,尽量别点外卖!

环球网资讯
2026-07-12 09:40:12
你见过最惊为天人的发型是什么样子?网友:震撼

你见过最惊为天人的发型是什么样子?网友:震撼

夜深爱杂谈
2026-07-08 21:42:51
伊朗官员向美方认错,承认不该向商船开火:都是强硬派误入歧途?

伊朗官员向美方认错,承认不该向商船开火:都是强硬派误入歧途?

音乐时光的娱乐
2026-07-12 12:56:11
正常家庭一年能存多少钱?真羡慕评论区的收入

正常家庭一年能存多少钱?真羡慕评论区的收入

康富贵碎碎念
2026-07-11 11:17:02
接听率暴跌70%,为啥中国人开始害怕接电话?

接听率暴跌70%,为啥中国人开始害怕接电话?

李砍柴
2026-07-06 22:30:04
秦可卿死得有多丢人?十三回里面一句话就说透了,作者根本不想瞒

秦可卿死得有多丢人?十三回里面一句话就说透了,作者根本不想瞒

掠影后有感
2026-07-11 10:11:13
成都养犬大变天!8月1日起正式执行,这6大变化关乎每个家庭

成都养犬大变天!8月1日起正式执行,这6大变化关乎每个家庭

奇思妙想生活家
2026-07-12 11:46:30
《Running Man》老将Gary近照曝光,形象大变认不出

《Running Man》老将Gary近照曝光,形象大变认不出

赴一场山海啊
2026-07-11 01:25:20
欧洲热浪一吹,义乌忙坏了:一台移动空调从20美元涨到200美元

欧洲热浪一吹,义乌忙坏了:一台移动空调从20美元涨到200美元

小柱解说游戏
2026-07-11 20:53:31
2026-07-12 14:12:49
新智元 incentive-icons
新智元
AI产业主平台领航智能+时代
15670文章数 66951关注度
往期回顾 全部

科技要闻

苹果诉OpenAI细节:一句“笑死”刺痛库克

头条要闻

女子遭前男友扼颈杀害 家属:男方身高190 她多次求饶

头条要闻

女子遭前男友扼颈杀害 家属:男方身高190 她多次求饶

体育要闻

被3个队友锁死,哈兰德以最憋屈的方式出局

娱乐要闻

迪丽热巴估计都无语了 亲自下场辟

财经要闻

美联储和市场将走向何方?

汽车要闻

纯电/增程双动力 一汽悦意08正式上市售9.99万起

态度原创

旅游
艺术
亲子
健康
军事航空

旅游要闻

京城近20家酒店联袂呈现“东方美学长廊”,为北京暑期文旅添一缕沉浸底色

艺术要闻

250米!大疆深圳湾“金字塔”总部,施工已全面铺开!

亲子要闻

生完孩子后,我不再不敢看他的眼睛

肝病、肾病患者注意!吃粘食要谨慎

军事要闻

伊朗宣布关闭霍尔木兹海峡:直至美国停止干涉该地区

无障碍浏览 进入关怀版