git详解(二)理解git对象
摘要: 本章是在初步了解git stage基础上继续的延伸,介绍什么是HEAD,master,这两个究竟是啥东西,有啥关系,为啥我们git log看到的commit log都是40位的16进制数字,这些数字是怎么生成的?为啥要这样表示?可不可以按数值递增来表示?通过这一篇的学习,我们会解决这些疑惑
关键字: git 对象,git commit,HEAD, master
1.git commit对象
我们在git工作目录下看一下提交历史
git log --pretty=raw
fox@fox:~/Documents/demo$ git log --pretty=raw
commit d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
tree fb090206bb44349ff5fc52d85fb94107f1d0ce92
parent ba7f561a2798f2b41a7131888bdbc58531ba89c5
author fox <leehaoran111@163.com> 1478439077 +0800
committer fox <leehaoran111@163.com> 1478439077 +0800
ok
commit ba7f561a2798f2b41a7131888bdbc58531ba89c5
tree a41e7c2f7c9bed661a30b996a4cb7468898c227c
parent 0e94145e01eb5da2420dd8a47d103aeab1dff44b
author fox <leehaoran111@163.com> 1478435045 +0800
committer fox <leehaoran111@163.com> 1478435045 +0800
commit
commit 0e94145e01eb5da2420dd8a47d103aeab1dff44b
tree c3b8bb102afeca86037d5b5dd89ceeb0090eae9d
author fox <leehaoran111@163.com> 1476806519 +0800
committer fox <leehaoran111@163.com> 1476806519 +0800
add test.txt
可以看到,一个提交里面有commit id,tree id,parent id,这分别表示啥呢?
这里我们介绍一个新的命令git cat-file,这个命令可以查看版本库对象的内容和类型信息,在分析git对象的时候十分有用,详情可以git help cat-file看一下(这儿也可以看出,最好的git教程就是git help,强烈建议遇到不懂的命令时先git help ,至少可以提高我们的学习能力,stay hungry,stay fool,开始时git help的越多,发现自己懂得越少,当我们git help发现很多都是熟悉的时候,对git应该算很熟悉了,当然离参与改进git还有段距离,我现在是属于第一阶段,因此一块学习,一块进步)
我们使用以下git cat-file
fox@fox:~/Documents/demo$ git cat-file -t d4c1f07
commit
fox@fox:~/Documents/demo$ git cat-file -p d4c1f07
tree fb090206bb44349ff5fc52d85fb94107f1d0ce92
parent ba7f561a2798f2b41a7131888bdbc58531ba89c5
author fox <leehaoran111@163.com> 1478439077 +0800
committer fox <leehaoran111@163.com> 1478439077 +0800
ok
fox@fox:~/Documents/demo$ git cat-file -t fb090206
tree
fox@fox:~/Documents/demo$ git cat-file -p fb090206
040000 tree 151ae54e1d0d34303df4d59ace2c023d0ef5278a hran
100644 blob 7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb test.txt
fox@fox:~/Documents/demo$ git cat-file -t ba7f561a
commit
fox@fox:~/Documents/demo$ git cat-file -p ba7f561a
tree a41e7c2f7c9bed661a30b996a4cb7468898c227c
parent 0e94145e01eb5da2420dd8a47d103aeab1dff44b
author fox <leehaoran111@163.com> 1478435045 +0800
committer fox <leehaoran111@163.com> 1478435045 +0800
commit
fox@fox:~/Documents/demo$ git cat-file -p 7aeee4f
hello world
git diff demo
amend some to test
fox@fox:~/Documents/demo$ ^C
fox@fox:~/Documents/demo$ git cat-file -p 151ae54
100644 blob be932f84e9104853c0dcf2088c60442320fff6ce test.c
fox@fox:~/Documents/demo$ git cat-file -p be932f84
s
可以看出,每次的提交都是一个commit对象,然后这个commit对象里面存放着一个tree对象和一个parent对象,另外还有提交信息,一个parent对象也是一个commit对象,一个tree对象包含blob对象或tree对象,blob对象里面存放的就是对应文件的内容,那这些对象保存到哪里了?当然是在.git/objects下面了hash值前位是目录,后38位是文件,当然这文件是不能直接打开的,更是不可以修改的,因为每一个hash值与文件内容都有关系,一旦修改了,就相当于破坏了对象库。
fox@fox:~/Documents/demo/.git/objects/7a$ ll
total 12
drwxrwxr-x 2 fox fox 4096 11月 6 20:23 ./
drwxrwxr-x 15 fox fox 4096 11月 6 21:31 ../
-r--r--r-- 1 fox fox 60 11月 6 20:23 eee4f72cc77cc564fcc3aa7fd03caea3542fcb
从上面的分析可以看出git对象结构如下
2 HEAD 与master
我们看下HEAD和master的commit id
fox@fox:~/Documents/demo$ git rev-parse HEAD
d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
fox@fox:~/Documents/demo$ git rev-parse master
d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
fox@fox:~/Documents/demo$ git log -1
commit d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
发现它们都一样,看下它们存在了.git的哪里
fox@fox:~/Documents/demo$ find .git -name HEAD -o -name master
.git/logs/HEAD
.git/logs/refs/heads/master
.git/HEAD
.git/refs/heads/master
我们先看下.git/HEAD
fox@fox:~/Documents/demo$ cat .git/HEAD
ref: refs/heads/master
fox@fox:~/Documents/demo$ cat .git/refs/heads/master
d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
这里可以看出HEAD是指向refs/heads/master的一个引用,而后者里面就是一个commit id
可以看出git 版本库结构应该如下图所示:
至于refs目录会在后面涉及到分支的时候详细介绍
3 40位的hash数字怎么来的
sha1(secure hash algorithm)是一个加密算法,可以保证根据2^64位以内的消息算出160bit的数字序列,也就是40个16进制的数字,这样有一个好处,就是人们不能根据随后生成的数字计算出消息内容,也不能让不同内容的文本计算出同样的hash数字,保证了数字序列的唯一性。
看下HEAD对应的commit信息
fox@fox:~/Documents/demo$ git cat-file commit HEAD
tree fb090206bb44349ff5fc52d85fb94107f1d0ce92
parent ba7f561a2798f2b41a7131888bdbc58531ba89c5
author fox <leehaoran111@163.com> 1478439077 +0800
committer fox <leehaoran111@163.com> 1478439077 +0800
ok
fox@fox:~/Documents/demo$ git cat-file commit HEAD |wc -c
203
fox@fox:~/Documents/demo$ (printf "commit 203\000";git cat-file commit HEAD)|sha1sum
d4c1f0765b0b58ce464d95989f2ebfe4094f4f54 -
对比一下HEAD的commit id
fox@fox:~/Documents/demo$ git rev-parse HEAD
d4c1f0765b0b58ce464d95989f2ebfe4094f4f54
是不是可以看出40位数字是怎么来的了呢?对象类型+字符数\000+内容
我们接下来验证一下:
fox@fox:~/Documents/demo$ git cat-file blob HEAD:test.txt
hello world
git diff demo
amend some to test
fox@fox:~/Documents/demo$ git cat-file blob HEAD:test.txt | wc -c
45
fox@fox:~/Documents/demo$ (printf "blob 45\000";git cat-file blob HEAD:test.txt)|sha1sum
7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb -
fox@fox:~/Documents/demo$ git rev-parse HEAD:test.txt
7aeee4f72cc77cc564fcc3aa7fd03caea3542fcb
是不是一样的呢?现在我们就知道了git里面的40位数字是怎么来的了
总结
本文延续上一文,介绍了git对象,HEAD, master的区别,还有git 里面的40位sha1码的来源。通过 这一文的学习,对git对象的理解又加深了不少,接下来会介绍git 的一些其它操作。
注:如果感觉到文章里面有些困惑,不用怀疑,一定是我讲的不好