网站备案的账号找不到,大型网上购物商城,基于python网站开发,深圳做h5网站制作本文以一个具体例子结合动图介绍了Git的内部原理#xff0c;包括Git是什么储存我们的代码和变更历史的、更改一个文件时#xff0c;Git内部是怎么变化的、Git这样实现的好处等等。TL;DR本文以一个具体例子结合动图介绍了Git的内部原理#xff0c;包括Git是什么储存我们的代码… 本文以一个具体例子结合动图介绍了Git的内部原理包括Git是什么储存我们的代码和变更历史的、更改一个文件时Git内部是怎么变化的、Git这样实现的好处等等。TL;DR本文以一个具体例子结合动图介绍了Git的内部原理包括Git是什么储存我们的代码和变更历史的、更改一个文件时Git内部是怎么变化的、Git这样实现的有什么好处等等。通过例子解释清楚上面这张动图让大家了解Git的内部原理。如果你已经能够看懂这张图了下面的内容可能对你来说会比较基础。本文是2019/11/24在深圳腾讯大厦2楼多功能厅举办的FCC前端分享会(freeCodeConf 2019 深圳站)上分享的文字版。视频https://www.bilibili.com/video/av77252063PPThttps://www.lzane.com/slide/git-under-the-hood前言近几年技术发展十分迅猛让部分同学养成了一种学习知识停留在表面只会调用一些指令的习惯。我们时常有一种“我会用这个技术、这个框架”的错觉等到真正遇到问题才发现事情没有那么简单。而Git也是一个大部分人都知道如何去使用它知道有哪些命令却只有少部分人知道具体原理的东西。了解一些底层的东西可以更好的帮你理清思路知道你真正在操作什么不会迷失在Git大量的指令和参数上面。Git是怎么储存信息的这里会用一个简单的例子让大家直观感受一下git是怎么储存信息的。首先我们先创建两个文件$ git init$ echo 111 a.txt$ echo 222 b.txt$ git add *.txtGit会将整个数据库储存在.git/目录下如果你此时去查看.git/objects目录你会发现仓库里面多了两个object。$ tree .git/objects.git/objects├── 58│ └── c9bdf9d017fcd178dc8c073cbfcbb7ff240d6c├── c2│ └── 00906efd24ec5e783bee7f23b5d7c941b0c12c├── info└── pack好奇的我们来看一下里面存的是什么东西$ cat .git/objects/58/c9bdf9d017fcd178dc8c073cbfcbb7ff240d6cxKOR0a044K%怎么是一串乱码这是因为Git将信息压缩成二进制文件。但是不用担心因为Git也提供了一个能够帮助你探索它的api git cat-file [-t] [-p] -t可以查看object的类型-p可以查看object储存的具体内容。$ git cat-file -t 58c9blob$ git cat-file -p 58c9111可以发现这个object是一个blob类型的节点他的内容是111也就是说这个object储存着a.txt文件的内容。这里我们遇到第一种Git objectblob类型它只储存的是一个文件的内容不包括文件名等其他信息。然后将这些信息经过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 4caaa1tree$ git cat-file -p 4caaa1100644 blob 58c9bdf9d017fcd178dc8c0... a.txt100644 blob c200906efd24ec5e783bee7... b.txt这里我们遇到了第二种Git object类型——tree它将当前的目录结构打了一个快照。从它储存的内容来看可以发现它储存了一个目录结构(类似于文件夹)以及每一个文件(或者子文件夹)的权限、类型、对应的身份证(SHA1值)、以及文件名。此时的Git仓库是这样的$ git cat-file -t 0c96bfcommit$ git cat-file -p 0c96bftree 4caaa1a9ae0b274fba9e3675f9ef071616e5b209author lzane 李泽帆 1573302343 0800committer lzane 李泽帆 1573302343 0800[] init接着我们发现了第三种Git object类型——commit它储存的是一个提交的信息包括对应目录结构的快照tree的哈希值上一个提交的哈希值(这里由于是第一个提交所以没有父节点。在一个merge提交中还会出现多个父节点)提交的作者以及提交的具体时间最后是该提交的信息。此时我们去看Git仓库是这样的到这里我们就知道Git是怎么储存一个提交的信息的了那有同学就会问我们平常接触的分支信息储存在哪里呢$ cat .git/HEADref: refs/heads/master$ cat .git/refs/heads/master0c96bfc59d0f02317d002ebbf8318f46c7e47ab2在Git仓库里面HEAD、分支、普通的Tag可以简单的理解成是一个指针指向对应commit的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的各种命令试一下你能不能够在上图将它们“可视化”出来这个很重要建议尝试一下。如果不能很好的将日常使用的指令“可视化”出来推荐阅读 图解Git一些有趣的问题有兴趣的同学可以继续阅读这部分不是文章的主要内容问题1为什么要把文件的权限和文件名储存在tree object里面而不是blob object呢想象一下修改一个文件的命名。如果将文件名保存在blob里面那么Git只能多复制一份原始内容形成一个新的blob object。而Git的实现方法只需要创建一个新的tree object将对应的文件名更改成新的即可原本的blob object可以复用节约了空间。问题2每次commitGit储存的是全新的文件快照还是储存文件的变更部分由上面的例子我们可以看到Git储存的是全新的文件快照而不是文件的变更记录。也就是说就算你只是在文件中添加一行Git也会新建一个全新的blob object。那这样子是不是很浪费空间呢?这其实是Git在空间和时间上的一个取舍思考一下你要checkout一个commit或对比两个commit之间的差异。如果Git储存的是问卷的变更部分那么为了拿到一个commit的内容Git都只能从第一个commit开始然后一直计算变更直到目标commit这会花费很长时间。而相反Git采用的储存全新文件快照的方法能使这个操作变得很快直接从快照里面拿取内容就行了。当然在涉及网络传输或者Git仓库真的体积很大的时候Git会有垃圾回收机制gc不仅会清除无用的object还会把已有的相似object打包压缩。问题3Git怎么保证历史记录不可篡改通过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 - OReilly Media (2012) 作为上面那本书的补充