Git 的半秘密空树对象可靠吗? 为什么没有一个符号名称?

Git 有一个众所周知的,或者至少在某种程度上众所周知的空树,它的 SHA1是:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(你可以在 git cat-file -tgit cat-file -p的任何回购协议中看到这一点,即使是新创建的回购协议)。[ 编辑于2020年: SHA-256空树散列 ID 是:

6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

我的问题显然提前了8年。]

如果你努力工作并且非常小心,你可以使用这个空树来存储一个没有文件的目录(参见 如何向 git 存储库添加一个空目录) ,虽然这不是一个很好的主意。

作为 git diff-tree的一个参数,它更有用,因为其中一个示例钩子是这样做的。

我想知道的是,

  1. 这种方法的可靠性如何ーー例如,某个未来版本的 git 会不会没有编号为 4b825dc642cb6eb9a060e54bf8d69288fbee4904的 git 对象?
  2. 为什么没有空树的符号名称(或者只有一个?)。

(创建符号名称的一种快速而简单的方法是将 SHA1放入,例如,.git/Nulltree。不幸的是,每次回购你都得这么做。似乎只是把神奇的数字在脚本,等等。我只是对神奇的数字有一种普遍的反感。)

24646 次浏览

这个帖子提到:

如果你不记得空树 sha1,你可以用:

git hash-object -t tree /dev/null

或者,正如 西罗 · 桑蒂利提议的 在评论中:

printf '' | git hash-object --stdin -t tree

或者,作为 在这里见过,来自 Colin Schimmelffing:

git hash-object -t tree --stdin < /dev/null

因此,我认为将命令的结果定义为空 sha1树(而不是依赖于“众所周知的值”)更安全。

注: Git 2.25.1(2020年2月)在 提交9c8a294中提出:

empty_tree=$(git mktree </dev/null)


# Windows (Command Prompt):
git mktree <NUL


# Windows (PowerShell):
$null | git mktree

并补充称:

作为一个历史记录,现在称为 repo_read_object_file()的函数在 346245a1bb中被教授了空树(“硬编码空树对象”,2008-02-13,Git v1.5.5-rc0—— 合并) ,而现在称为 oid_object_info()的函数在 C4d9986f5f中被教授了空树(“ sha1_object_info: 也检查 cached_object存储”,2011-02-07,Git v1.7.4.1)。


注意,当作者希望它的第一次提交为空时,你会看到 SHA1在一些 GitHub 回购中弹出(参见博客文章“ 如何初始化 Git 存储库”) :

$ GIT_AUTHOR_DATE="Thu, 01 Jan 1970 00:00:00 +0000" GIT_COMMITTER_DATE="Thu, 01 Jan 1970 00:00:00 +0000" git commit --allow-empty -m 'Initial commit'

会给你:

Empty tree SHA1

(看到树 SHA1了吗?)

您甚至可以在空提交的基础上重新设置现有历史记录(参见“ Git: 如何作为第一个提交插入一个提交,转移所有其他提交?”)

在这两种情况下,您都不依赖于该空树的确切 SHA1值。
你只需要遵循 最佳实践,用第一个空提交初始化回购


要做到这一点:

git init my_new_repo
cd my_new_repo
git config user.name username
git config user.email email@com


git commit --allow-empty -m "initial empty commit"

这将生成一个针对您的回购、用户名、电子邮件、创建日期的 SHA1提交(这意味着提交本身的 SHA1每次都不同)。
但是该提交引用的树将是 4b825dc642cb6eb9a060e54bf8d69288fbee4904,即空树 SHA1。

git log --pretty=raw


commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <vonc@laposte.net> 1381232247 +0200
committer VonC <vonc@laposte.net> 1381232247 +0200


initial empty commit

要仅显示提交树(显示提交树 SHA1) :

git show --pretty=format:%T 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
4b825dc642cb6eb9a060e54bf8d69288fbee4904

如果该提交(引用一个空树)确实是 第一提交,那么可以使用以下方法显示该空树 SHA1:

git log --pretty=format:%h --reverse | head -1 | xargs git show --pretty=format:%T
4b825dc642cb6eb9a060e54bf8d69288fbee4904

(甚至可以在 Windows 上使用 Gnu On Windows命令)


作为 评论如下,使用 git diff <commit> HEAD,这将显示当前分支 HEAD 中的所有文件:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD

注意: 空树值是在 强 > cache.h中正式定义的。

#define EMPTY_TREE_SHA1_HEX \
"4b825dc642cb6eb9a060e54bf8d69288fbee4904"

自从 Git 2.16(2018年第一季度)以来,它被用在一个不再(仅仅)与 SHA1绑定的结构中,如 提交 eb0ccfd所示:

切换空树和 blob 查找以使用散列抽象

中表示当前哈希算法的 current_hash抽象切换 empty_tree_oidempty_blob_oid的使用 使用。

更多信息请参见“ 为什么 Git 不使用更现代的 SHA?”: 它是 < a href = “ https://en.wikipedia.org/wiki/SHA-2”rel = “ nofollow noReferrer”> SHA-2 ,因为 Git 2.19(2018年第三季度)


使用 Git 2.25(Q12020) ,测试正在为 SHA-2过渡期做准备,并且涉及到空树。

参见 提交 FA26d5e提交 cf02be8第38季第26集犯罪提交0370b35犯罪现场调查,第二季,第12集犯罪现场调查,第四季,第2集79bedc提交840624f提交 FA26d5e0,提交 FA26d5e1,提交 FA26d5e2,提交 FA26d5e3(2019年10月28日)和 提交 FA26d5e4,提交 FA26d5e5(2019年10月5日)。
(由 朱尼奥 · C · 哈马诺 gitster于2019年11月10日在 提交28014c1合并)

t/oid-info : 添加空树和空 blob 值

签名: Brian M. Carlson

测试套件最终将学习如何使用 SHA-1以外的算法运行。为此,教 test_oid系列函数如何查找空的 blob 和空的树值,以便使用它们。

所以 t/oid-info/hash-info现在包括:

rawsz sha1:20
rawsz sha256:32


hexsz sha1:40
hexsz sha256:64


zero sha1:0000000000000000000000000000000000000000
zero sha256:0000000000000000000000000000000000000000000000000000000000000000


algo sha1:sha1
algo sha256:sha256


empty_blob sha1:e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
empty_blob sha256:473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813


empty_tree sha1:4b825dc642cb6eb9a060e54bf8d69288fbee4904
empty_tree sha256:6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321

SHA2“ 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321”是新的 SHA1“ 4b825dc642cb6eb9a060e54bf8d69288fbee4904”空树。

我写了一篇博客文章,其中提到了两种查找 hash 的不同方法: http://colinschimmelfing.com/blog/gits-empty-tree/

如果由于某种原因它发生了变化,您可以使用下面的两种方法来找到它。然而,我很有信心把大麻放进去。Bashrc 别名等等,我不认为它会很快改变。至少可能是 git 的一个主要版本。

这两种方式是:

  1. 上面的答案是: git hash-object -t tree --stdin < /dev/null
  2. 只需初始化一个空的回购,然后在新的回购中运行 git write-tree-散列将由 git write-tree 输出。

下面是关于如何创建空树提交的答案,即使在存储库尚未为空的情况下也是如此。 Https://stackoverflow.com/a/14623458/9361507

但我更喜欢“空”而不是标签,简单的方法是:

git tag empty $(git hash-object -t tree /dev/null)

因为标记可以直接指向树状,而不需要提交。 现在获取工作树中的所有文件:

git diff --name-only empty

统计数据也是一样:

git diff --stat empty

所有文件区别如下:

git diff empty

检查所有文件中的空白:

git diff --check empty