繁体   English   中英

git 如何“取消散列”其内部对象?

[英]How does git "unhash" its internal objects?

最近我阅读了有关 git 内部结构的信息,发现在引擎盖下 git 散列了它的对象:

$ echo 'test content' | git hash-object -w --stdin

d670460b4b4aece5915caf5c68d12f560a9fe3e4

它如何“取消哈希”其 hash 对象及其内容?

$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4

test content

Git 不会取消散列其对象。 它使用 hash 作为查找键,就像hash 表一样。

git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4

Git 使用 d670460b4b4aece5915caf5c68d12f560a9fe3e4 查找内容。 它可以在两个地方, .git/objects/ (又名“松散对象”)或packfile

在上述情况下, Git 将寻找.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 如果该文件存在,那么它会解压缩它,viola,这就是你的内容。

您可以通过使用openssl zlib -d <.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4解压缩文件自己看到这一点。


Git 会定期将松散的对象清理到“包文件”中。 这些是二进制文件,其中包含许多对象的信息。 这比单个文件更有效。 这些在细节上有点复杂,但 SHA1 hash 再次用于查找文件中的内容。 您的示例可能看起来像这样。

d670460b4b4aece5915caf5c68d12f560a9fe3e4 blob   61 60 285843732

Git 使用此信息来获取内容,具体如何工作很复杂。 如果您愿意,可以阅读有关 血腥细节的信息

它如何“取消哈希”其 hash 对象及其内容?

它在索引中找到 object。 如果您查看.git/objects目录,我怀疑您会找到一个名为“d6”的目录,其中包含一个名为70460b4b4aece5915caf5c68d12f560a9fe3e4的文件。 我的理解是该文件包含 object 的内容 - 尽管可能以某种方式压缩。

但是,凭空变出信息并没有什么魔力。 (特别是,如果您在没有object 的存储库中使用相同git cat-file命令,它将失败,如下所示:

fatal: Not a valid object name d670460b4b4aece5915caf5c68d12f560a9fe3e4

Git 将某些内容转换为 sha1 值(并且该跟踪可以是 static(例如,用于提交)或动态(例如,用于分支)),但这些 sha1 值引用存储为完整值,不涉及“unhashing”。

例子:

$ mkdir /tmp/test
$ cd /tmp/test
$ git init
$ touch .gitignore
$ git add .gitignore
$ git commit -m .gitignore

# One commit is now created, so how many objects have git created?
$ find .git/objects -type f
.git/objects/82/e3a754b6a0fcb238b03c0e47d05219fbf9cf89
.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391
.git/objects/8e/816c8b0c098993d0b018cb4d16ce45a43c7ab0

# One commit
$ cat .git/refs/heads/main 
8e816c8b0c098993d0b018cb4d16ce45a43c7ab0
$

# which references one tree object
$ git ls-tree main
100644 blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391    .gitignore
$

# which references one (empty) file
$ git cat-file blob e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
$

因此,提交 object 存储了一个硬编码的完整树引用,并且它永远无法更改 - 引用值是计算提交 id 的固有基础,所以如果你重新设置或修改提交,你最终会得到不同的提交 id。

另一方面,随着提交的添加/更改/删除,git 会不断更新分支:

$ echo '*.bak' >> .gitignore
$ git add .gitignore 
$ git commit -m "Ignore backup files"
$ cat .git/refs/heads/main 
351ac7498b2eeb73d91a01e5e3270b2bb8ae47a3
$ git log --oneline
351ac74 (HEAD -> main) Ignore backup files
8e816c8 .gitignore
$

然而,这里存储的 sha1 参考也完全满了,不需要以任何方式计算它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM