GIT中数据的存储与组织
我们经常使用一些Git的命令,例如
checkout
,commit
等命令,这些都是高级命令,有一些比较底层的命令,对我们查看数据很有帮助
命令 | 说明 |
---|---|
git hash-object | 存储数据对象 |
find .git/objects -type f | 查看objects 目录下的文件 |
git cat-file -p [hashcode] | 显示存储的内容 |
GIT的数据目录
### 初始化Git仓库
$ git init
$ cd .git
$ ll
total 24
-rw-r--r-- 1 sparrow staff 23B 12 24 16:01 HEAD
drwxr-xr-x 2 sparrow staff 64B 12 24 16:01 branches
-rw-r--r-- 1 sparrow staff 137B 12 24 16:01 config
-rw-r--r-- 1 sparrow staff 73B 12 24 16:01 description
drwxr-xr-x 13 sparrow staff 416B 12 24 16:01 hooks
drwxr-xr-x 3 sparrow staff 96B 12 24 16:01 info
drwxr-xr-x 4 sparrow staff 128B 12 24 16:01 objects
drwxr-xr-x 4 sparrow staff 128B 12 24 16:01 refs
重要的目录列表:
目录名 | 目录作用 |
---|---|
HEAD | 指向目前被检出的分支 |
index | 文件保存暂存区的信息 |
objects | 存储所有数据内容 |
refs | 目录存储指向数据(分支)的提交对象的指针 |
GIT数据的存储
如何存储文件
# sparrow @ localhost in ~/Documents/learning/test on git:master o [16:07:34] C:1
$ find .git/objects -type f
# sparrow @ localhost in ~/Documents/learning/test on git:master o [16:07:47]
$ echo '测试内容' | git hash-object -w --stdin
a936e260776b0c97788d90fb9e87e133c6401364
# sparrow @ localhost in ~/Documents/learning/test on git:master o [16:09:16]
$ find .git/objects -type f
.git/objects/a9/36e260776b0c97788d90fb9e87e133c6401364
# sparrow @ localhost in ~/Documents/learning/test on git:master o [16:09:21]
$ git cat-file -p a936e260776b0c97788d90fb9e87e133c6401364
测试内容
我们可以看到数据的存储方式:一个文件对应一条内容,以该内容加上特定头部信息一起的 SHA-1 校验和为文件命名。校验和的前两个字符用于命名子目录,余下的 38 个字符则用作文件名。
如何存储变更的文件
# sparrow @ localhost in ~/Documents/learning/test on git:master o [17:26:43]
$ echo '1111' > 1.txt
# sparrow @ localhost in ~/Documents/learning/test on git:master x [17:29:38]
$ git hash-object -w 1.txt
5f2f16bfff90e6620509c0cf442e7a3586dad8fb
# sparrow @ localhost in ~/Documents/learning/test on git:master x [17:29:45]
$ find .git/objects -type f
.git/objects/5f/2f16bfff90e6620509c0cf442e7a3586dad8fb
.git/objects/a9/36e260776b0c97788d90fb9e87e133c6401364
# sparrow @ localhost in ~/Documents/learning/test on git:master x [17:30:21]
$ echo '2222' > 1.txt
# sparrow @ localhost in ~/Documents/learning/test on git:master x [17:31:14]
$ git hash-object -w 1.txt
c7dc989f8044a4fcf16361414998e14694e1ac7e
# sparrow @ localhost in ~/Documents/learning/test on git:master x [17:31:23]
$ find .git/objects -type f
.git/objects/5f/2f16bfff90e6620509c0cf442e7a3586dad8fb
.git/objects/c7/dc989f8044a4fcf16361414998e14694e1ac7e
.git/objects/a9/36e260776b0c97788d90fb9e87e133c6401364
上面的命令,是存储了一个txt文件,之后修改这个文件,再次存储,可以看到文件变更后又存储了一个新的文件。但是有个明显的问题就是,我们始终没有看到存储的文件名称。
GIT的文件种类
文件类型 | 描述 | 存储的信息 |
---|---|---|
commit | 提交组建 | 每次提交之后产生,会把所有文件信息创建一个tree文件,以及提交信息,用户信息 |
tree | 文件树 | 存储这个tree下有哪些文件,有文件类型,文件hash值,文件名称 |
blob | 文件 | 文件的具体内容(会被压缩) |
GIT:Commit && Tree
### 新增一个1.txt文件,并且提交:
$ git commit -m'第一次提交'
[master (root-commit) f2e5a15] 第一次提交
1 file changed, 1 insertion(+)
create mode 100644 1.txt
$ git cat-file -p master^{tree}
100644 blob c7dc989f8044a4fcf16361414998e14694e1ac7e 1.txt
$ find .git/objects -type f
.git/objects/66/58043fa729b52ab982f5fd48aa35a3992dbca0
.git/objects/f2/e5a15e35c55cd773496dd6092953a2deeaaf29
.git/objects/c7/dc989f8044a4fcf16361414998e14694e1ac7e
$ git cat-file -p 66580
100644 blob c7dc989f8044a4fcf16361414998e14694e1ac7e 1.txt
$ git cat-file -t f2e5a
commit
$ git cat-file -p f2e5a
tree 6658043fa729b52ab982f5fd48aa35a3992dbca0
author sparrow <chwangyanan@foxmail.com> 1545645214 +0800
committer sparrow <chwangyanan@foxmail.com> 1545645214 +0800
第一次提交
从上面可以看出,如果我们进行了新的提交,就会出现一个新的commit文件,然后这个文件中包含一个tree文件的 hash值,而这个tree文件的内容则包含文件名,当然也可以是tree的名称(相当于目录的概念)
提交记录Commit
### 新增一个文件 */dir1/2.txt*
$ find .git/objects -type f
.git/objects/66/58043fa729b52ab982f5fd48aa35a3992dbca0
.git/objects/e5/cbfdee257934ed2cf026ce17ca868f3a4b1705
.git/objects/c7/dc989f8044a4fcf16361414998e14694e1ac7e
.git/objects/ee/4cc7e06ea6b72d9d92534e37cc0ee5fe8622cf
.git/objects/f2/e5a15e35c55cd773496dd6092953a2deeaaf29
.git/objects/e4/8f67e7f3128750710269e1baccadd83ac151ad
.git/objects/8a/666e85a8ec9b8d4a2bad19c976892ac1bc948d
$ git cat-file -p e5cbf
tree ee4cc7e06ea6b72d9d92534e37cc0ee5fe8622cf
parent f2e5a15e35c55cd773496dd6092953a2deeaaf29
author sparrow <chwangyanan@foxmail.com> 1545645896 +0800
committer sparrow <chwangyanan@foxmail.com> 1545645896 +0800
带目录的提交
$ git cat-file -p e48f6
dir1->111
$ git cat-file -p 8a666
100644 blob e48f67e7f3128750710269e1baccadd83ac151ad 2.txt
$ git cat-file -p ee4cc
100644 blob c7dc989f8044a4fcf16361414998e14694e1ac7e 1.txt
040000 tree 8a666e85a8ec9b8d4a2bad19c976892ac1bc948d dir1
可以发现:
- 目录被储存为一个tree文件。
- 提交记录里面多了parent一行,指向前一次提交的hash。
- 1.txt的记录会被再次存储
HEAD指向
$ cat .git/HEAD
ref: refs/heads/master
看下HEAD,发现指向ref中的文件
$ cat .git/refs/heads/master
e5cbfdee257934ed2cf026ce17ca868f3a4b1705
会发现有一个hash值,这个值就是第二次提交后生成的commit文件的hash值。
分支的信息
### 新建dev分支
$ git branch dev
$ git branch
* master
dev
### 进入.git/refs/heads目录,查看分支信息
$ cd .git/refs/heads
$ ll
total 16
-rw-r--r-- 1 sparrow staff 41B 12 24 18:28 dev
-rw-r--r-- 1 sparrow staff 41B 12 24 18:04 master
$ cat dev
e5cbfdee257934ed2cf026ce17ca868f3a4b1705
$ cat master
e5cbfdee257934ed2cf026ce17ca868f3a4b1705
可以看到,dev 和 master 指向同一个Commit,HEAD指向这里的master
### 通过拷贝文件的方式创建一个新的分支
$ cp dev dev2
$ git branch
* master
dev
dev2
### 这个时候可以去看下,HEAD文件已经指向dev2