gh-liu / myNote

0 stars 0 forks source link

对`git`四种`object`的理解 #1

Open gh-liu opened 5 months ago

gh-liu commented 5 months ago

假设你有一个文件夹projectName,希望对这个文件夹进行版本管理,你可能想到的办法:

  1. 复制整个文件夹
  2. 给新复制的文件夹重命名,加上版本后缀,比如projectName_Version2

然后,你会发现,不同版本之间的文件夹,比如projectName_Version2projectName_Version3之间的差异可能只有少数几个文件,而剩余的文件是相同的,所以你会希望:

  1. 相同的文件只存储一份,然后在不同版本的文件夹中,相同的文件不存储实际文件内容,只储存实际文件内容的地址

然后,你希望在每次复制文件夹的时候,添加一些额外信息,比如:为什么复制?复制的时间?谁复制的?

最后,你希望标记某个重要的复制节点,比如projectName_Version12

在上面的场景中,已经出现了git的四种对象:文件对象(blob)、树对象(tree)、提交对象(commit)、标签对象(tag)

blob对象就是文件,tree对象就是文件夹,commit对象指向一棵树同时携带一些额外信息,tag对象指向一个commit对象同时携带一些额外信息。

gh-liu commented 5 months ago

git的四种对象:文件对象(blob)、树对象(tree)、提交对象(commit)、标签对象(tag),本质上是一个文件,其文件名是一个哈希字符串。

# 生成哈希
git hash-object 文件路径
# 使用 -w 参数时,会将对象写入git对象数据库
git hash-object -w 文件路径

# 打印git对象中的内容
git cat-file -p 哈希
# 打印git对象的类型
git cat-file -t 哈希

git代码仓库示例:

git clone https://github.com/git/git.git
cd  git

提交对象(commit)

通过 git log 查询到git的第一个 commit 的哈希是 e83c5163316f89bfbde7d9ab23ca2e25604af290

git cat-file -t e83c5163316f89bfbde7d9ab23ca2e25604af290
# 输出
commit
git cat-file -p e83c5163316f89bfbde7d9ab23ca2e25604af290
# 输出
tree 2b5bfdf7798569e0b59b16eb9602d5fa572d6038
author Linus Torvalds <torvalds@ppc970.osdl.org> 1112911993 -0700
committer Linus Torvalds <torvalds@ppc970.osdl.org> 1112911993 -0700

Initial revision of "git", the information manager from hell

从 commit 的内容中,可以看到指向的 tree 对象,哈希为2b5bfdf7798569e0b59b16eb9602d5fa572d6038,和一些额外信息

树对象(tree)

git cat-file -t 2b5bfdf7798569e0b59b16eb9602d5fa572d6038
# 输出:
tree
git cat-file -p 2b5bfdf7798569e0b59b16eb9602d5fa572d6038
# 输出:
100644 blob a6bba79ba1f46a1bbf7773449c3bd2bb9bf48e8b    Makefile
100644 blob 27577f76849c09d3405397244eb3d8ae1d11b0f3    README
100644 blob 98a32a9ad39883c6d05a000a68511d4b1ee2b3c7    cache.h
100644 blob 74a0a234dd346fff51c773aa57d82fc4b83a8557    cat-file.c
100644 blob 840307af0cfaab31555795ce7175d5e9c9f981a0    commit-tree.c
100644 blob 25dc13fe101b219f74007f3194b787dd99e863da    init-db.c
100644 blob c924a6e0fc4c36bad6f23cb87ee59518c771f936    read-cache.c
100644 blob 1b47742d8cbc0d98903777758b7b519980e7499e    read-tree.c
100644 blob b8522886a15db861508fb6d03d4d88d6de912a4b    show-diff.c
100644 blob 5085a5cb53ee52e1886ff6d46c609bdb2fc6d6cd    update-cache.c
100644 blob 921f981353229db0c56103a52609d35aff16f41b    write-tree.c

可以看到 tree 对象内容为一系列的文件,包含文件权限、对象类型(blob文件类型、tree树类型)、文件对象哈希、文件名

文件对象(blob)

git cat-file -t  a6bba79ba1f46a1bbf7773449c3bd2bb9bf48e8b
# 输出:
blob
git cat-file -p 2b5bfdf7798569e0b59b16eb9602d5fa572d6038
# 输出:
CFLAGS=-g
CC=gcc
......省略文件中间内容
backup: clean
        cd .. ; tar czvf dircache.tar.gz dir-cache

文件对象的内容,就是进行版本控制的文件的内容

标签对象(tag)

还没有提到标签对象,以标签v1.0.0为例:

git rev-parse v1.0.0
# 获取到哈希为:
# f665776185ad074b236c00751d666da7d1977dbe
git cat-file -t  f665776185ad074b236c00751d666da7d1977dbe
# 输出:
tag
git cat-file -p f665776185ad074b236c00751d666da7d1977dbe
# 输出:
object c2f3bf071ee90b01f2d629921bb04c4f798f02fa
type commit
tag v1.0.0
tagger Junio C Hamano <junkio@cox.net> 1135152060 -0800

GIT 1.0.0
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQBDqOh7wMbZpPMRm5oRAg+OAJ90pNi/fq5rguVou1PSxx95PYCVeACfbnZM
nN/PlwOWKA3rW8EPmWO4BzE=
=TCRg
-----END PGP SIGNATURE-----

可以看到tag对象的内容为:指向的对象的哈希与类型、tag名、创建tag的人、还有签名