Git底层原理和结构

基础
一、数据结构
  • Git的底层存储时以文件快照实现的,对版本的存储是通过文件快照整体进行存储,重复的文件通过指针索引源文件,不重复存储;而SVN/CVS存储的是各版本之间的差异。

    文件快照(snapshot):概念上的复制+物理上的引用

    • git会把出现变更的文件直接拷贝(但不是复制粘贴这么简单,git会处理、压缩),形成新的blob,而不是与上一个版本的差异diff;(切换速度快, 其他版本控制需要做merge,空间换时间)
      (快照的作用就相当于将旧文件所占的空间保留下来,并且保存一个引用,而新文件中会继续使用与旧文件内容相同部分的磁盘空间,不同部分则写入新的磁盘空间。总的来说git其实也算是保存diff的方式,只不过是在文件系统层次上实现的。)
    • 如果没有改变,快照其实是链接上一个版本。
    • git gc是一个打包指令,打包之前变动的文件,会保存当前最新版本的整个文件,之前的版本只保存diff(因为最新版本用得多)。这个指令可以主动触发,也可以在git push,或者变动文件过多的时候自动触发。通过git的底层指令能够还原出打包之前的信息。
git object
  • Git是一个内容寻址文件系统,Git的核心部分是一个键值对数据库;向 Git 仓库中插入任意类型的内容,它会返回一个唯一的键,通过该键可以在任意时刻再次取回该内容。

  • .git/object目录即对象数据库。

    右键打开Git Bash:
    在这里插入图片描述

    初始化一个版本库,Git会对object目录初始化,创建pack,info子目录,均为空。

1. blob对象

在这里插入图片描述
echo "contents" > a.txt会在工作目录创建a.txt,写入contents。即在数据结构中创建blob对象节点。
echo "222" | git hash-object -w --stdin会返回存储在Git库中的唯一键。(-w 选项会指示该命令不要只返回键,还要将该对象写入数据库中。)

git会根据文件内容生成校验和(SHA-1哈希值,40位),以校验和为索引。

将待存储的数据外加一个头部信息(header)一起做 SHA-1 校验运算而得的校验和。
SHA-1算法(Secure Hash Algorithm 1):一种密码散列函数。

在这里插入图片描述
git cat-file -t 前六位哈希 可以让 Git 告诉我们其内部存储的任何对象类型,只要给定该对象的 SHA-1 值。
git cat-file -p 前六位哈希 查看文件内容
在这里插入图片描述
blob数据对象中,并没有保存文件名,仅保存了文件内容。

为什么要把文件的权限和文件名储存在Tree object 里面而不是Blob object呢?
节省空间,因为相同的文件内容在Git仓库里面只有一个Blob Object, 不管有多少个指针指向他。

2. tree对象
  • tree object可以解决文件名保存的问题,一个树对象包含了一条或多条树对象记录(tree entry),每条记录含有一个指向数据对象或者子树对象的 SHA-1 指针,以及相应的模式、类型、文件名信息。
    在这里插入图片描述
  • 通常,Git 根据某一时刻暂存区(即 index 区域,下同)所表示的状态创建并记录一个对应的树对象, 如此重复便可依次记录(某个时间段内)一系列的树对象。
3. commit对象
  • commit对象存储的是提交信息,可以保存作者信息,快照时间,已经为什么保存快照等信息。

    commit对象内容
    在这里插入图片描述
    每次commit的时候,都生成一个commit的对象。它先指定一个顶层树对象,代表当前项目快照; 然后是可能存在的父提交(前面描述的提交对象并不存在任何父提交); 之后是作者/提交者信息(依据你的 user.name 和 user.email 配置来设定,外加一个时间戳); 留空一行,最后是提交注释。
    tree对象保存当前暂存区所有文件的blob对象,每个blob对象都通过SHA1生成一个索引作为key,指向该文件的压缩(保存整个文件)。

也可以通过git命令创建blob,tree,commit对象,建立他们的指向关系,不需要借助上层命令(git add/commit),同样可以提交文件。

Git 内部原理 - Git 对象

总结,blob类型只是存储文件的内容,不包括文件名等其他信息。将这些信息经过SHA1哈希算法得到对应的哈希值,作为这个object在Git仓库的唯一标识。tree对象

二、执行命令时的结构变化

新建文件后,Git会创建blob object:
在这里插入图片描述

git add
  • 将新添加的文件或者改动放入Git的暂存区(Index)。
git commit
  • git commit -am '[+] init' 后,会多出来两个object。
  • tree object,从它存储的内容来看可以发现它存储了一个目录结构(类型文件夹),以及每一个文件(或者子文件夹)的权限、类型、对应身份证(SHA1值)以及文件名。
    在这里插入图片描述
  • 提交后会生成commit object,存储提交信息,包括对应目录结构的快照tree的哈希值,上一个提交的哈希值,提交的作者以及提交的具体时间,该提交的信息。
    在这里插入图片描述
  • 此时Git仓库是这样的:
    在这里插入图片描述
  • 在Git仓库中,HEAD、分支、普通的Tag可以理解成一个指针,指向对应commit的SHA1值。

    HEAD:当前分支版本顶端的别名,也就是在当前分支最近的一个提交
    在这里插入图片描述
    本质上是一个key-value的数据库加上默克尔树形成的有向无环图(DAG)。
    整体的仓库状态:
    在这里插入图片描述

修改本地文件
  • 将本地文件a.txt由111改为333。
    在这里插入图片描述
  • git add a.txt,在git仓库中新建了一个blob object,并且更新索引指向新建的blob object。
    在这里插入图片描述
  • git commit -m 'update' 提交修改,Git首先根据当前索引生成一个tree object。然后创建新的commit object,将这次的提交信息存储,父提交只想上一个commit,组成一条链记录变更历史。最后将master分支的指针移到新的commit。
    在这里插入图片描述
常用命令及结构变化
  • git checkout:移动HEAD指针

    • git checkout -b dev :创建分支dev并切换到这个分支(HEAD指向这个分支)
      在这里插入图片描述
    • git checkout branchname:切换到某个分支(HEAD指针指向该分支的commit节点,索引指向也相应更新,然后由索引内容更新到本地工作目录)。
  • git reset:回滚,会移动HEAD和master。

    • git reset --soft HEAD~: 将Git仓库的提交回滚到前一个(移动HEAD和master),暂存区和工作目录不变;HEAD~是前一个,HEAD~2是第二个祖先提交…HEAD~n;
      在这里插入图片描述
    • git reset HEAD~ :等价于git reset --mixed HEAD~默认选项,暂存区和Git仓库回滚到前一个提交,工作目录不变。(将你当前的改动从缓存区中移除,但是这些改动还留在工作目录中。)
      在这里插入图片描述
    • git reset --hard HEAD~:工作目录也回到指定的提交。
      在这里插入图片描述
  • checkout和reset区别:

    git reset soft,hard,mixed之区别深解

  • git revert:撤销一个提交的同时会创建一个新的提交。这是一个安全的方法,因为它不会重写提交历史。比如,git revert HEAD~2会找出倒数第二个提交,然后创建一个新的提交来撤销这些更改,然后把这个提交加入项目中。

其他命令
  • git status
  • git log
  • git cat-file -t xxxxxx git cat-file -p xxxxxx:查看二进制压缩
    head指针的变化
三、分支合并
  • 三向合并
  • 合并策略:fast-forward、recursive递归、ours&therirs、octopus
四、实用技巧
  • 误删分支:git rebase 节点哈希值()

  • 获得干净的工作目录:git stash push [-u],能用git stash pop恢复

    git reset --hard HEAD,git checkout -f都会丢失文件。

  • git log:可以显示所有提交过的版本信息

  • git reflog:可以查看所有分支的所有操作记录(包括已经被删除的 commit 记录和 reset 的操作)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值