跳转至

commit 的sha值是如何计算的

[1].https://jingsam.github.io/2018/06/09/git-hash.html

0.使用git show 查看commit相关信息

commit bfe4078b84eec85c1cafdb0a26f3fd93b581727e (HEAD -> master)
Author: root <root@hideto>
Date:   Thu Oct 22 10:53:28 2020 +0800

    init commit

diff --git a/1.txt b/1.txt
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/1.txt
@@ -0,0 +1 @@
+hello

在上面的输出中 index其实就是file_sha

1.commit 的相关信息,使用如下命令获得

git cat-file commit HEAD

输出内容如下

[root@hideto:~/testrepo]# git cat-file commit HEAD
tree c560751e61b3849c60561912a2045ae86b92d506
author root <root@hideto> 1603335208 +0800
committer root <root@hideto> 1603335208 +0800

init commit

仅仅这些信息还不够,还要加上一个commit NNN的信息,获得这个信息需要执行

printf ('commit %s\0') $(git cat-file commit HEAD | wc -c)

输入如下

[root@hideto:~/testrepo]# printf "commit %s\0" $(git cat-file commit HEAD | wc -c)
commit 148

将这些信息组合在一起使用sha加密即可得到commit 的sha 值

[root@hideto:~/testrepo]# (printf "commit %s\0" $(git cat-file commit HEAD |wc -c);git cat-file commit HEAD)|shasum
bfe4078b84eec85c1cafdb0a26f3fd93b581727e  -

我们再添加一些内容,然后执行git show 查看结果

[root@hideto:~/testrepo]# git show 
commit 7e2136ebf78dd82c8f16f6e5fe4d9bd195c12c6e (HEAD -> master)
Author: root <root@hideto>
Date:   Thu Oct 22 11:14:18 2020 +0800

    second commit

diff --git a/1.txt b/1.txt
index ce01362..410ca14 100644
--- a/1.txt
+++ b/1.txt
@@ -1 +1,2 @@
 hello
+bye

可以看到起始的filesha 就是上次保存的filesha

再查看一下commit 信息,

root@hideto:~/testrepo]# git cat-file commit HEAD
tree 6343f2489ddcb41637a6172dc24cd01f3242b165
parent bfe4078b84eec85c1cafdb0a26f3fd93b581727e
author root <root@hideto> 1603336458 +0800
committer root <root@hideto> 1603336458 +0800

second commit

可以看到相比于第一次commit ,增加了一个parents 的内容,看一下parents 里面包含的内容

git cat-file -p bfe4078b84eec85c1cafdb0a26f3fd93b581727e
tree c560751e61b3849c60561912a2045ae86b92d506
author root <root@hideto> 1603335208 +0800
committer root <root@hideto> 1603335208 +0800

init commit

可以看到panrents sha值所代表的内容正是上一次commit 提交的信息,就像是一个链条一个链接到了上一次commit.

下面我们来看一下tree 对象里面的内容

[root@hideto:~/testrepo]# git cat-file -p c560751e61b3849c60561912a2045ae86b92d506
100644 blob ce013625030ba8dba906f756967f9e9ca394464a    1.txt

因为这次commit 其实只是变更了一个文件所以tree 对象只包含的一个blob,如果修改了其他文件夹下面的文件,那么会多出一个tree对象,然后再查看tree 对象可以查看这个文件夹下面的内容,总之如果是blob对象,那么就不可再分了。

下面我们查看一下这个blob 对象里面的内容

[root@hideto:~/testrepo]# git cat-file -p ce013625030ba8dba906f756967f9e9ca394464a
hello

上面这个是第二次commit 的panrents 对象(即第一次commit) 包含的tree 下面的blob 对象所对应的内容。

我们在来看一下第二次commit 的tree 对象

[root@hideto:~/testrepo]# git cat-file -p 6343f2489ddcb41637a6172dc24cd01f3242b165
100644 blob 410ca1402253bbbd2d9eaf4b95f02bce95eb4583    1.txt

再看一下blob 对象

[root@hideto:~/testrepo]# git cat-file -p 410ca1402253bbbd2d9eaf4b95f02bce95eb4583
hello
bye
[root@hideto:~/testrepo]# 

那么现在问题就变成如何得到blob 对象的sha值

1.查看当前文件的内容

[root@hideto:~/testrepo]# cat 1.txt 
hello
bye

2.生成sha值

[root@hideto:~/testrepo]# cat 1.txt | git hash-object -w --stdin
410ca1402253bbbd2d9eaf4b95f02bce95eb4583

blob 对象其实就是使用git 内置的一个函数hash-object 来基于文件内容进行计算sha值,如果文件内容相同,那么计算出来的sha值也是相同的,那么就可以降低冗余来减少硬盘空间的占用

或者使用如下命令也可以达到相同的效果

[root@hideto:~/testrepo]# printf "hello\nbye\n" |git hash-object -w --stdin
410ca1402253bbbd2d9eaf4b95f02bce95eb4583

commit,blob 对象的sha知道了以后,现在的问题就剩下了tree 对象的sha值是如何计算的。

​ ---待续