.git的数据结构一

本文主要探讨git 的add commit 操作的数据是如何进行记录的

1. 新建一个git仓库

chuangchuang@chuang:~/work/temp$ cd gittest/
chuangchuang@chuang:~/work/temp/gittest$ ll
总用量 8
drwxrwxr-x 2 chuangchuang chuangchuang 4096 11月 11 18:20 ./
drwxrwxr-x 4 chuangchuang chuangchuang 4096 11月 11 18:20 ../
chuangchuang@chuang:~/work/temp/gittest$ git init
初始化空的 Git 仓库于 /home/chuangchuang/work/temp/gittest/.git/
chuangchuang@chuang:~/work/temp/gittest$ 
chuangchuang@chuang:~/work/temp/gittest$ ll
总用量 12
drwxrwxr-x 3 chuangchuang chuangchuang 4096 11月 11 18:21 ./
drwxrwxr-x 4 chuangchuang chuangchuang 4096 11月 11 18:20 ../
drwxrwxr-x 7 chuangchuang chuangchuang 4096 11月 11 18:21 .git/

2.看一下.git的结构

chuangchuang@chuang:~/work/temp/gittest$ tree .git/
.git/
├── branches
├── config
├── description
├── HEAD
├── hooks
│   ├── applypatch-msg.sample
│   ├── commit-msg.sample
│   ├── post-update.sample
│   ├── pre-applypatch.sample
│   ├── pre-commit.sample
│   ├── prepare-commit-msg.sample
│   ├── pre-push.sample
│   ├── pre-rebase.sample
│   └── update.sample
├── info
│   └── exclude
├── objects
│   ├── info
│   └── pack
└── refs
    ├── heads
    └── tags

9 directories, 13 files

3,添加一些东西

3.1 刚开始的时候并没有在路径上显示分支,即使使用git branch -a 也没有

chuangchuang@chuang:~/work/temp/gittest$ git branch -a     
chuangchuang@chuang:~/work/temp/gittest$ 

3.2 在往里面添加过文件

chuangchuang@chuang:~/work/temp/gittest$ touch aa.txt  //1
chuangchuang@chuang:~/work/temp/gittest$ ll         //2
总用量 12
drwxrwxr-x 3 chuangchuang chuangchuang 4096 11月 11 19:00 ./
drwxrwxr-x 4 chuangchuang chuangchuang 4096 11月 11 18:20 ../
-rw-rw-r-- 1 chuangchuang chuangchuang    0 11月 11 19:00 aa.txt
drwxrwxr-x 7 chuangchuang chuangchuang 4096 11月 11 19:00 .git/

3.3 查看.git目录(只有objects目录有变化)

├── objects
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── info
│   └── pack

这个时候发现在objects下面多了一个id e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
查看该文件下有什么

chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
chuangchuang@chuang:~/work/temp/gittest[master*]$ 
//显示的是什么都没有,这个是add 添加到stage区的文件,因为是空文件,所以没有内容

3.4 执行了commit 操作以后就有了分支

chuangchuang@chuang:~/work/temp/gittest$ git add aa.txt   //1
chuangchuang@chuang:~/work/temp/gittest$ git commit -a -m "aa.txt tianjia"  //2
[master (根提交) a3c8eff] aa.txt tianjia
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 aa.txt
// 接下来的路径中就显示了master分支
chuangchuang@chuang:~/work/temp/gittest[master*]$ ll   //3
总用量 12
drwxrwxr-x 3 chuangchuang chuangchuang 4096 11月 11 19:00 ./
drwxrwxr-x 4 chuangchuang chuangchuang 4096 11月 11 18:20 ../
-rw-rw-r-- 1 chuangchuang chuangchuang    0 11月 11 19:00 aa.txt
drwxrwxr-x 8 chuangchuang chuangchuang 4096 11月 11 19:00 .git/

4,再次看看.git中都有写什么

.git
├── branches
├── objects
│   ├── a3
│   │   └── c8effc24eeb66de97a66b073c6d62c48fbc9ed
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── f1
│   │   └── 3f51556efabe074d5b255eabcdd3ec33520c55
│   ├── info
│   └── pack
└── refs
    ├── heads
    │   └── master
    └── tags

4.1 可以看到object中多了两个目录,每个目录下多了一个文件,这个其实就是每次操作的hash值
执行git log 看看当前有多少提交

chuangchuang@chuang:~/work/temp/gittest[master*]$ git log -1 --pretty=raw  //注意这里的是 -1 是数字不是字母
commit a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
tree f13f51556efabe074d5b255eabcdd3ec33520c55
author chuang  1510398041 +0800
committer chuang  1510398041 +0800

    aa.txt tianjia
chuangchuang@chuang:~/work/temp/gittest[master*]$ git version

可以看到有一个commit id ,是 a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
还有一个是本次操作的快照id f13f51556efabe074d5b255eabcdd3ec33520c55
使用git cat-file解压文件看一下

//可以看到这个里面存储的就是commit 提交的时候填入的信息
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
tree f13f51556efabe074d5b255eabcdd3ec33520c55
author chuang  1510398041 +0800
committer chuang  1510398041 +0800

aa.txt tianjia

// 这个tree中存放的也是一个引用,指向了真正存放文件内容 的文件
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p f13f51556efabe074d5b255eabcdd3ec33520c55
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    aa.txt

//因为这个文件刚刚创建,什么都没有
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
chuangchuang@chuang:~/work/temp/gittest[master*]$ 

//查看一下仓库中的文件记录,就是最开始add的那个id

chuangchuang@chuang:~/work/temp/gittest[master*]$ git ls-tree -l HEAD
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391       0    aa.txt

可以看到文件记录是e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
这个代表了仓库中存储的该原始文件

5 执行git add 操作后的结构

chuangchuang@chuang:~/work/temp/gittest[master*]$  echo '1 di yi ci wang li tian jia nei rong' >> aa.txt 
chuangchuang@chuang:~/work/temp/gittest[master*]$ git add .
chuangchuang@chuang:~/work/temp/gittest[master*]$ git status
位于分支 master
要提交的变更:
  (使用 "git reset HEAD <文件>..." 以取消暂存)

    修改:     aa.txt

这个时候再看


chuangchuang@chuang:~/work/temp/gittest[master*]$ tree .git/
.git/
├── branches
├── objects
│   ├── a3
│   │   └── c8effc24eeb66de97a66b073c6d62c48fbc9ed
│   ├── e4
│   │   └── 626567ec9ae5a6f3abd77af37c25a85ec4e7f1
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── f1
│   │   └── 3f51556efabe074d5b255eabcdd3ec33520c55
│   ├── info
│   └── pack


可以看到多了一个文件
e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1
通过list-files 查看缓存区的文件

chuangchuang@chuang:~/work/temp/gittest[master*]$ git ls-files -s
100644 e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1 0   aa.txt

6,再次执行git commit 后的结果

6.1 执行commit

chuangchuang@chuang:~/work/temp/gittest[master*]$ git commit -a -m "di er ci ti jiao test"
[master 45776d6] di er ci ti jiao test
 1 file changed, 1 insertion(+)

6.2 查看.git 的object目录为(截取了一部分)

              
├── objects
│   ├── 45
│   │   └── 776d6cb67571cfe31656fb1d114e520c9e0ab2
│   ├── 68
│   │   └── d98b1781c29d1df8b4ac7b6d457bccecf9756e
│   ├── a3
│   │   └── c8effc24eeb66de97a66b073c6d62c48fbc9ed
│   ├── e4
│   │   └── 626567ec9ae5a6f3abd77af37c25a85ec4e7f1
│   ├── e6
│   │   └── 9de29bb2d1d6434b8b29ae775ad8c2e48c5391
│   ├── f1
│   │   └── 3f51556efabe074d5b255eabcdd3ec33520c55
│   ├── info
│   └── pack

可以看到又多了两条记录
6.3 通过git log查看commit

chuangchuang@chuang:~/work/temp/gittest[master*]$ git log -2 --pretty=raw
commit 45776d6cb67571cfe31656fb1d114e520c9e0ab2  //这个是第二次提交产生的commit id
tree 68d98b1781c29d1df8b4ac7b6d457bccecf9756e     // 这个是第二次提交产生的快照
parent a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
author chuang  1510452772 +0800
committer chuang  1510452772 +0800

    di er ci ti jiao test

commit a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
tree f13f51556efabe074d5b255eabcdd3ec33520c55
author chuang  1510398041 +0800
committer chuang  1510398041 +0800

    aa.txt tianjia

6.3.1 git log 分析

45776d6cb67571cfe31656fb1d114e520c9e0ab2 是这次commit 产生的commit id
68d98b1781c29d1df8b4ac7b6d457bccecf9756e 是本次提交的快照
parent a3c8effc24eeb66de97a66b073c6d62c48fbc9ed 表明了上次提交的 commit id 是a3c8effc24eeb66de97a66b073c6d62c48fbc9ed 对应了第一次提交的commit id

6.3.2 查看当前本地仓库的文件

chuangchuang@chuang:~/work/temp/gittest[master*]$ git ls-tree -l HEAD
100644 blob e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1      37    aa.txt

是保存id 为e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1 的文件
这个对应了5中add操作在object目录下产生的id,说明这个时候已经从暂存区(stage)进入了仓库

6.3.3 分析这些id之间的关系

//这里可以看出,commit id中存储的就是 commit的时候填写进去的信息
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p 45776d6cb67571cfe31656fb1d114e520c9e0ab2
tree 68d98b1781c29d1df8b4ac7b6d457bccecf9756e
parent a3c8effc24eeb66de97a66b073c6d62c48fbc9ed
author chuang  1510452772 +0800
committer chuang  1510452772 +0800

di er ci ti jiao test

// tree中记录的依然是一个指针,指向了blob类型的  e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p 68d98b1781c29d1df8b4ac7b6d457bccecf9756e
100644 blob e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1    aa.txt

//可以看到这个里面存储的是真正的文件内容,也就是add操作产生的id
chuangchuang@chuang:~/work/temp/gittest[master*]$ git cat-file -p e4626567ec9ae5a6f3abd77af37c25a85ec4e7f1
1 di yi ci wang li tian jia nei rong

7 ,一次添加多个文件

7.1 两次修改原来的aa.txt

//第一次操作,修改aa.txt 会产生一个新的index id
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ echo 'another test san'>> aa.txt 
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ cat aa.txt 
1 di yi ci wang li tian jia nei rong
another test san
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git add .
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git ls-files -s
100644 5c3079aa5ec819e560b4b548e0ea4efb39be239f 0   aa.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git cat-file -p 5c3079aa5ec819e560b4b548e0ea4efb39be239f

//第二次操作修改 aa.txt 会产生新的 index id
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ echo 'third test'>>aa.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ cat aa.txt 
1 di yi ci wang li tian jia nei rong
another test san
third test
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git add .
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git ls-files -s
100644 658bed4dcaeec2c18e04af192971e7093b3c7ab9 0   aa.txt




7.2 添加3个文件,

//添加bb.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ touch bb.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ echo 'bb text'>> bb.txt 

//添加cc.txt dd.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ vi cc.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ 
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ vi dd.txt

7.3 查看缓冲区index

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git ls-files -s
100644 658bed4dcaeec2c18e04af192971e7093b3c7ab9 0   aa.txt
100644 90593bc026fb525e8bf56485d3101a389dac4417 0   bb.txt
100644 9af3475341efe72b1fc0b4109055436b2700c1b9 0   cc.txt
100644 f224fbe59efc4467313afe938f836488d84ff3b3 0   dd.txt

可以看到每个文件分别有一条

7.4 执行commit之后的git log结构
commit

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git commit -m "一次提交了四个"
[dev d4a8da9] 一次提交了四个
 4 files changed, 5 insertions(+)
 create mode 100644 bb.txt
 create mode 100644 cc.txt
 create mode 100644 dd.txt


查看仓库

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git ls-tree -l HEAD
100644 blob 658bed4dcaeec2c18e04af192971e7093b3c7ab9      65    aa.txt
100644 blob 90593bc026fb525e8bf56485d3101a389dac4417       8    bb.txt
100644 blob 9af3475341efe72b1fc0b4109055436b2700c1b9      12    cc.txt
100644 blob f224fbe59efc4467313afe938f836488d84ff3b3       8    dd.txt
chuangchuang@chuang:~/work/temp/tempgit[dev*]$ 

查看日志

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git log -1 --pretty=raw
commit d4a8da99076957a318aafff68fab06f81862fafc
tree bfdc957c7bb165a8f53c13b49261c683ca5c8c7f
parent 45776d6cb67571cfe31656fb1d114e520c9e0ab2
author chuang  1510484509 +0800
committer chuang  1510484509 +0800

7.5 分别看看该次commit的 log 记录对应结构
查看commit

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git cat-file -p d4a8da99076957a318aafff68fab06f81862fafc
tree bfdc957c7bb165a8f53c13b49261c683ca5c8c7f
parent 45776d6cb67571cfe31656fb1d114e520c9e0ab2
author chuang  1510484509 +0800
committer chuang  1510484509 +0800

一次提交了四个

查看 commit对应的tree,也就是当次操作的快照

chuangchuang@chuang:~/work/temp/tempgit[dev*]$ git cat-file -p bfdc957c7bb165a8f53c13b49261c683ca5c8c7f
100644 blob 658bed4dcaeec2c18e04af192971e7093b3c7ab9    aa.txt
100644 blob 90593bc026fb525e8bf56485d3101a389dac4417    bb.txt
100644 blob 9af3475341efe72b1fc0b4109055436b2700c1b9    cc.txt
100644 blob f224fbe59efc4467313afe938f836488d84ff3b3    dd.txt

可以看到,这里的快照的id关联的 index的id是刚才add操作产生的四个id

8 总结

git的数据信息的管理都是在.git/objects目录下进行管理的

git的add

  1. 会在object下
    为每一个变化的文件产生一个压缩文件来记录改变后的文件(是改变后的完整文件)

commit 操作

  1. 产生一个commit id记录本次commit的一些描述性信息
  2. 产生一个关联commit的快照信息的文件
  3. 2中产生的文件内容包含指向add产生的压缩文件的指针

你可能感兴趣的:(.git的数据结构一)