25-git-21-原理

git是如何存储信息的

1、初始化仓库,新建文件,并添加到暂存区

git init
echo '111' > a.txt
echo '222' > b.txt
git add *.txt
// 查看一下当前的git仓库中的内容
tree .git

├─hooks    
├─info     
├─objects  
│  ├─4e    
│  ├─71    
│  ├─info  
│  └─pack  
└─refs     
    ├─heads
    └─tags 
    
ls -a .git/objects/4e
./  ../  f5d11d3b99f88fb9f70b694de01db16c56ed50

ls -a .git/objects/71
./  ../  70f7d93c37a8861f0e6816780b2881ad5f58d2

// 查看一下f5d11d3b99f88fb9f70b694de01db16c56ed50文件中的内容
cat .git/objects/4e/f5d11d3b99f88fb9f70b694de01db16c56ed50
x☺K□□OR0gP744TW□☻∟.♥☻
// 打印出来的是一些乱码,原因是因为git对储存的内容做了二进制压缩

2、cat-file

git cat-file [-t] [-p]

-t 打印文件类型

-p 打印文件具体内容

git cat-file -t 4ef5d1
blob
git cat-file -p 4ef5d1
'111'

3、git object

git 储存信息的最小单元,对象数据库包含四类对象。git对象创建完成后均不可变更。

  • Blob:包含二进制数据,它们是文件内容。只要文件内容改变,就会在对象数据库中生成一个blob对象。注意,blob对象只保存文件内容,不含文件名和文件存储位置等信息。如果文件名改变,或者文件储存位置改变,不会生成新的blob对象。
  • Tree:blob对象的集合,以及它们的文件名和权限。一个tree对象描述一个时点上的一个目录。
  • Commit:描述一个时点上的项目状态,包含一条log信息,一个tree对象和指向父节点(parent commits)的指针。第一个commit对象没有父节点。
    • 记录 root tree SHA1
    • 记录 parent commit SHA1
    • 记录作者、时间和 commit message
  • tag

4、sha1哈希算法

111 -> 4ef5d11d3b99f88fb9f70b694de01db16c56ed50

每个git对象都有一个哈希值,哈希值可以理解为我们的身份证号

4ef5d11d3b99f88fb9f70b694de01db16c56ed50就是内容为111类型为blob的git对象的身份证号,我们可以通过4ef5d11d3b99f88fb9f70b694de01db16c56ed50找到这个git对象

5、git commit

git commit -m 'init'
tree .git

├─hooks
├─info
├─logs
│  └─refs
│      └─heads
├─objects
│  ├─39
│  ├─4e
│  ├─5f
│  ├─71
│  ├─info
│  └─pack
└─refs
    ├─heads
    └─tags
    
 ls -a .git/objects/39
./  ../  bd985025d281e7c1d1c9493c90156fb9e26ea0

ls -a .git/objects/5f
./  ../  3f16e16db5faec1bf71fab36cbad24fbddfd39
git cat-file -t 5f3f16
tree

git cat-file -p 5f3f16
100644 blob 4ef5d11d3b99f88fb9f70b694de01db16c56ed50    a.txt
100644 blob 7170f7d93c37a8861f0e6816780b2881ad5f58d2    b.txt
git cat-file -t 39bd98
commit

git cat-file -p 39bd98
tree 5f3f16e16db5faec1bf71fab36cbad24fbddfd39

6、HEAD指针和分支

cat .git/HEAD
ref: refs/heads/master

cat .git/refs/heads/master
39bd985025d281e7c1d1c9493c90156fb9e26ea0

可以看出,HEAD指针指向分支指针,分支指针指向最新的commit

HEAD、分支、普通的Tag可以简单的理解成是一个指针,指向对应commit的SHA1值。

7、为什么要把文件的权限和文件名储存在Tree object里面而不是Blob object呢?

因为更改一个文件名就需要新建一个Blob object,假如文件很大的话,会很占空间,而Tree object体积相对很小

8、当你修改了其中一个文件,创建一个新的commit后

git的三个分区

  • 工作目录 ( working directory ):操作系统上的文件,所有代码开发编辑都在这上面完成。
  • 索引( index or staging area ):可以理解为一个暂存区域,这里面的代码会在下一次commit被提交到Git仓库。
  • Git仓库( git repository ):由Git object记录着每一次提交的快照,以及链式结构记录的提交变更历史。

转载

李泽帆

https://www.lzane.com/tech/git-internal/