git 基本原理

git 基本原理

什么是git ?

Git是一个分布式版本控制系统(DVCS),它与集中式版本控制系统,如SVN有很大的不同。它们最大的差别是如何处理数据:

  • SVN等大多数版本控制系统存储的数据是一系列记录项目文件变更的文件
  • Git存储的数据则更像是一个微型文件系统的一系列快照,即快照流

如下图:
svn
(svn存储的是文件的变更)

git
(git在每个版本下,都会生成一个文件快照)

这样的好处在于,可以轻松的回溯到任意一个版本,而不是比较每次变更的地方。

git是如何管理文件的

1. 使用哈希,哈希是一个系列的加密算法(Git 底层采用的是 SHA-1),各个不同的哈希算法虽然加密强度不同,但是有以下几个共同点:

  • 不管输入数据的数据量有多大,使用同一个哈希算法,得到的加密结果长度固定(git使用的是40位)
  • 哈希算法确定,输入数据确定,输出结果保证不变
  • 哈希算法确定,输入数据有变化,输出结果一定有变化,而且通常变化很大
  • 哈希算法不可逆
  • 哈希算法中不区分英文大小写

2. Git 把数据看作是小型文件系统的一组快照。每次提交更新时 Git 都会对当前的全部文件制作一个快照并保存这个快照的索引。为了高效,如果文件没有修改,Git 不再重新存储该文件,而是只保留一个链接指向之前存储的文件。所以 Git 的工作方式可以称之为快照流。

git是如何存储文件的

  • git 是一个内容寻址系统
  • git 的核心部分是一个简单的键对数据库

一个栗子

git init 
复制代码

首先初始化一个git仓库

可以使用vim编辑器新建一个内容为 11111 的 1.txt

ls -al
复制代码

这时查看文件,可以发现文件列表不仅有1.txt 还有一个 .git的文件

brew install tree
brew install watch
复制代码

安装第一个代表用树形结构展示你的文件,另一个是监视文件的变化

watch -n .5 tree .git 
复制代码

可以新开一个窗口,执行此命令,表示0.5秒监听一次文件的变化

可以看到git的树形结构
tree

rm -r .git/hooks
复制代码

为了方便看的清楚删除多余的hooks,重点关注objects和refs
tree2

这时当我们执行 git add 1.txt 之后可以发现git树也相应的发生了变化,objects里面多了一个结构 (此时文件在暂存区,还未保存版本)

  • f7 (c6dd01 …)

tree3

git cat-file -t f7c6
git cat-file -p f7c6
复制代码

当使用第一个命令的时候可以看出 文件类型为 blob ,使用第二个命令可以看出文件存储的内容

接下里执行 git commit -m “first commit” 命令后又多出来两条存储信息

  • 87 (d37b26)
  • fa (d18af3)

tree4

通过 git cat-file -t / -p 可看出 对应的文件类型及存储信息

  • 87 (d37b26) 文件类型是一个tree , 存储的是文件类型为 blob ,hash值为f7 (c6dd01 …) ,以及1.txt 这个名称

可以看出blob文件只存储具体内容,而文件名称是存储在tree类型里面的,这就说明假如我们有10份内容一模一样的文件 ,其实git 只帮我们存储了一份 ,但是tree中是要记录10次的

  • fa (d18af3) 文件类型是一个commit , 存储的是这一次commit 提交的信息 — “first commit” , 并且会存储一个tree ,指向87 (d37b26),这样通过每个版本的提交信息就能找到相关信息 ,可以任意版本回溯

可以在新建一个文件 例如 2.txt ,存储的内容与1.txt 保持一致,当执行git add 2.txt 时 其实git是不会再次存储此文件的

此时在新建一个3.txt文件,3.txt ,存储的内容与前两次不一样 ,这次执行git add . 时git就会存储它,并又多了一个存储信息

  • 5a (cf9b10)

tree5

用git cat-file -p 5acf 命令可查看此条信息内存储的正是刚才3.txt的信息,现在的文件状态是 2.txt 和 3.txt 都只在暂存区,还未执行commit 操作,现在执行

git commit -m "second commit" 
复制代码

这时又会多出两条存储信息

  • ed (cb4edd)
  • c4 (884dd6)

tree6

我们执行查看命令的时候发现

  • ed (cb4edd) 这条信息 存储的信息有

    • 有个tree 指向c4 (884dd6)
    • 有个parent 指向 fa (d18af3),上次commit的信息
    • 第二次提交的信息
  • c4 (884dd6) 存储的是具体内容

小总结

  1. 以上我们可以发现git的几个对象:
  • blob:存储的是数据
  • tree: 一个指向文件名、内容和其他tree的指针
  • commit: 作者信息、提交信息、以及指向parent上一次提交的指针
  1. 过程如下:

tree7

上述图片是现有的一个文件系统,现在对1.txt做出了改变,即下图

tree8

此时git在代码库也备份了一个最新的1.txt, 此时当执行git commit 命令的时候,tree就会生成一个新的索引指向这个文件 ,而且代码库的tree 也会根据暂存区的一个tree 的索引新生成一个索引。commit也会新生成一个commit,有一个指向新的tree的指针,和上一次parent的指针,即下图。

tree9

git 分支的变化

分支合并冲突:

  1. fast-forward:

tree9

tree9

tree9

当没有冲突就直接修改指针指向即可

  1. no-fast-forward

tree9

tree9

当有冲突的时候,会创建一个新指针,同时指向master和dev

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享