Git内部原理(1)

Git本质上是一套内容寻址文件系统,在此之上提供了VCS的用户界面。

Git底层命令(plumbing) vs 高层命令(porcelain)

Git的高层命令包括checkout、branch、remote等总共约30个,这些命令主要交由用户在命令行界面中使用。而除了高层命令之外,Git还提供一些底层命令,这些命令通常不用于命令行界面,而是交由其它工具和自定义脚本使用。

.Git的目录结构

git init 命令会在文件夹中创建一个.git目录,用于存放所有版本管理相关的内容,其目录结构如下:

1
2
3
4
5
6
7
8
9
10
$ ls
HEAD
branches/
config
description
hooks/
index
info/
objects/
refs/

在该目录下,Git的核心保存在HEAD文件和 index objects refs目录下。

  • objects 存储所有的数据内容
  • refs存储指向数据的提交对象的指针
  • HEAD 文件指向当前分支
  • index 包含了暂存区的信息

Git 对象

Git是一套内容寻址文件系统,本质是通过键值寻找Git对象。

内容寻址文件系统: 它允许插入任意类型的内容,并返回一个键值(40位);通过该键值可以在任何时候提取这部分内容。

数据对象

下面来演示如何向git中插入一个Git数据对象,并获取键值。

git第一个底层命令hash-object

1
2
$ echo 'test content' | git hash-object -w --stdin
d670460b4b4aece5915caf5c68d12f560a9fe3e4

这样,就为git系统添加了一个对象,其内容为:

1
2
$ find .git/objects -type f
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4

表示 Git 存储数据内容的方式──为每份内容生成一个文件,取得该内容与头信息的 SHA-1 校验和,创建以该校验和前两个字符为名称的子目录,并以 (校验和) 剩下 38 个字符为文件命名 (保存至子目录下)。

git第二个底层命令cat-file -p 查看对象内容 -t 查看对象类型

通过git cat-file 命令可以查看Git对象,例如:

1
2
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
blob

树对象

创建一个index,然后将这个index加入一个已有的tree中

大专栏  Git内部原理(1)">commit对象

可以通过调用 commit-tree 命令创建一个提交对象,为此需要指定一个树对象的 SHA-1 值,以及该提交的父提交对象

Git 引用

Git下的引用类型,是指向某个SHA-1值的指针。所有的引用对象都保存在.git/refs文件夹下。引用类型帮助我们记住提交的位置。

如何变更Git的引用类型指向的SHA-1

1
2
    git update-ref refs/heads/test cac0ca # 将test指向cac0ca提交

以下将介绍几个重要的引用对象

HEAD引用

HEAD文件指向一个引用对象,用于标识当前分支。我们可以通过如下方式读取HEAD

1
cat .git/HEAD

Git提供修改HEAD的命令symbolic-ref

1
git symbolic-ref HEAD refs/heads/test

符号引用对象(symbolic-ref)是特殊的引用对象,它指向一个引用对象,而不是常规的SHA-1值。所以symbolic-ref命令可以更新包括HEAD在内的所有符号引用对象。

标签引用

Git中除了数据对象、树对象、提交对象,还有 标签对象标签对象类似于一个提交对象,包括标签创建者、日期、注释以及一个指向提交对象的指针。反过来,我们可以对任意一个对象打标签,而不局限在提交对象。

标签对象存储在.git/refs/tags文件夹下。

远程引用

如果你添加了一个远程版本库并对其执行过推送操作,Git 会记录下最近一次推送操作时每一个分支所对应的值,并保存在 refs/remotes 目录下。

远程分支存储在目录refs/remotes/[origin]下,其中[origin]是远程仓库的别名。

远程引用和分支(位于 refs/heads目录下的引用)之间最主要的区别在于,远程引用是只读的。 虽然可以 git checkout 到某个远程引用,但是 Git 并不会将 HEAD 引用指向该远程引用。因此,你永远不能通过 commit 命令来更新远程引用。 Git 将这些远程引用作为记录远程服务器上各分支最后已知位置状态的书签来管理。

Git 包文件

当我们对一个较大的文件作了微小的修改,并提交之后,git仓库中会生成一个新的数据对象,其内容与现有内容几乎一致,差别只有一小块修改过的内容。

如果 Git 只完整保存其中一个,再保存另一个对象与之前版本的差异内容,岂不更好?

Git 最初向磁盘中存储对象时所使用的格式被称为“松散(loose)”对象格式。 但是,Git 会时不时地将多个这些对象打包成一个称为“包文件(packfile)”的二进制文件,以节省空间和提高效率。 当版本库中有太多的松散对象,或者你手动执行 git gc 命令,或者你向远程服务器执行推送时,Git 都会这样做。

git包文件存储在.git/objects/pack/目录中。

通过调用命令git verify-package可以查看打包内容:

1
$ git verify-pack -v .git/objects/pack/pack-978e03944f5c581011e6998cd0e9e30000905586.idx

Git 打包对象时,会查找命名及大小相近的文件,并保存最新的版本的完整内容文件不同版本之间的差异内容

原文地址:https://www.cnblogs.com/lijianming180/p/12376220.html