git git的半秘密空树对象可靠吗,为什么没有符号名呢?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9765453/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 06:36:50  来源:igfitidea点击:

Is git's semi-secret empty tree object reliable, and why is there not a symbolic name for it?

git

提问by torek

Git has a well-known, or at least sort-of-well-known, empty tree whose SHA1 is:

Git 有一个众所周知的,或者至少是众所周知的空树,它的 SHA1 是:

4b825dc642cb6eb9a060e54bf8d69288fbee4904

(you can see this in any repo, even a newly created one, with git cat-file -tand git cat-file -p).

(您可以在任何 repo 中看到这一点,甚至是新创建的,带有git cat-file -tgit cat-file -p)。

If you work hard and are very careful you can sort of use this empty tree to store a directory that has no files (see answer to How do I add an empty directory to a git repository), although it's not really a great idea.

如果您努力工作并且非常小心,您可以使用这个空树来存储一个没有文件的目录(请参阅如何将空目录添加到 git 存储库的答案),尽管这并不是一个好主意。

It's more useful as one argument to git diff-tree, which one of the sample hooks does.

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

What I'm wondering is,

我想知道的是,

  1. how reliable is this—i.e., will some future version of git not have a git object numbered 4b825dc642cb6eb9a060e54bf8d69288fbee4904?
  2. Why is there no symbolic name for the empty tree (or is there one?).
  1. 这有多可靠——也就是说,未来的 git 版本会不会没有编号的 git 对象4b825dc642cb6eb9a060e54bf8d69288fbee4904
  2. 为什么空树没有符号名称(或者有?)。

(A quick and dirty way to create a symbolic name is to put the SHA1 in, e.g., .git/Nulltree. Unfortunately you have to do this for every repo. Seems better to just put the magic number in scripts, etc. I just have a general aversion to magic numbers.)

(一个快速和肮脏的方式来创建一个符号名称是摆在,例如,SHA1 .git/Nulltree。不幸的是,你必须为每个回购做到这一点。看来,最好是干脆把剧本中的幻数,等等。我只是有一个普遍的厌恶。到魔术数字。)

采纳答案by VonC

This threadmentions:

这个线程提到:

If you don't remember the empty tree sha1, you can always derive it with:

如果你不记得空树 sha1,你总是可以通过以下方式推导出它:

git hash-object -t tree /dev/null

Or, as fxscproposes in the comments:

或者,正如fxsc在评论中提出的那样

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

Or, as seen here, from Colin Schimmelfing:

或者,如此处所见,来自Colin Schimmelfing

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

So I guess it is safer to define a variable with the result of that command as your empty sha1 tree (instead of relying of a "well known value").

所以我想用该命令的结果定义一个变量作为你的空 sha1 树(而不是依赖“众所周知的值”)更安全。

Note: Git 2.25.1 (Feb. 2020) proposes in commit 9c8a294:

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

empty_tree=$(git mktree </dev/null)
# Windows:
git mktree <NUL

And adds:

并补充说:

As a historical note, the function now known as repo_read_object_file()was taught the empty tree in 346245a1bb("hard-code the empty tree object", 2008-02-13, Git v1.5.5-rc0 -- merge), and the function now known as oid_object_info()was taught the empty tree in c4d9986f5f("sha1_object_info: examine cached_objectstore too", 2011-02-07, Git v1.7.4.1).

作为历史记录,现在已知的函数repo_read_object_file()是在346245a1bb(“硬编码空树对象”,2008-02-13,Git v1.5.5-rc0 -- merge)中教授的,而现在已知的函数正如oid_object_info()c4d9986f5f中教导的空树(“ sha1_object_info:也检查cached_object商店”,2011-02-07,Git v1.7.4.1)。



Note, you will see that SHA1 pop up on some GitHub repo when the author wants its first commit to be empty (see blog post "How I initialize my Git repositories"):

请注意,当作者希望其第一次提交为空时,您将看到 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'

Will give you:

会给你:

Empty tree SHA1

空树 SHA1

(See the tree SHA1?)

(看到树 SHA1 了吗?)

You can even rebase your existing history on top of that empty commit (see "git: how to insert a commit as the first, shifting all the others?")

您甚至可以在该空提交之上重新建立现有历史记录(请参阅“ git:如何将提交作为第一个插入,转移所有其他提交?”)

In both cases, you don't rely on the exact SHA1 value of that empty tree.
You simply follow a best practice, initializing your repo with a first empty commit.

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



To do that:

要做到这一点:

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"

That will generate a commit with a SHA1 specific to your repo, username, email, date of creation (meaning the SHA1 of the commit itself will be different every time).
But the tree referenced by that commit will be 4b825dc642cb6eb9a060e54bf8d69288fbee4904, the empty tree SHA1.

这将生成一个带有特定于您的存储库、用户名、电子邮件、创建日期的 SHA1 的提交(意味着提交本身的 SHA1 每次都会不同)。
但是该提交引用的树将是4b825dc642cb6eb9a060e54bf8d69288fbee4904空树 SHA1。

git log --pretty=raw

commit 9ed4ff9ac204f20f826ddacc3f85ef7186d6cc14
tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904      <====
author VonC <[email protected]> 1381232247 +0200
committer VonC <[email protected]> 1381232247 +0200

    initial empty commit

To show just the tree of a commit (display the commit tree SHA1):

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

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

If that commit, referencing an empty tree, is indeed your firstcommit, you can show that empty tree SHA1 with:

如果该提交(引用一棵空树)确实是您的第一次提交,则您可以使用以下命令显示该空树 SHA1:

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

(and that even works on Windows, with Gnu On Windowscommands)

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



As commented below, using git diff <commit> HEAD, this will show all your file in the current branch HEAD:

正如下面的评论,使用git diff <commit> HEAD,这将显示在目前的分公司负责所有的文件:

git diff --name-only 4b825dc642cb6eb9a060e54bf8d69288fbee4904 HEAD


Note: that empty tree value is formally defined in cache.h.

注意:空树值在cache.h.

#define EMPTY_TREE_SHA1_HEX \
    "4b825dc642cb6eb9a060e54bf8d69288fbee4904"

Since Git 2.16 (Q1 2018), it is used in a structure which is no longer tied to (only) SHA1, as seen in commit eb0ccfd:

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

Switch empty tree and blob lookups to use hash abstraction

Switch the uses of empty_tree_oidand empty_blob_oidto use the current_hashabstraction that represents the current hash algorithm in use.

切换空树和 blob 查找以使用哈希抽象

切换使用empty_tree_oidempty_blob_oid使用current_hash代表当前使用的散列算法的抽象。

See more at "Why doesn't Git use more modern SHA?": it is SHA-2, since Git 2.19 (Q3 2018)

请参阅“为什么 Git 不使用更现代的 SHA?”:它是SHA-2,因为 Git 2.19(2018 年第三季度)



With Git 2.25 (Q1 2020), tests are preparing for a SHA-2 transition, and is involving the empty tree.

在 Git 2.25(2020 年第一季度)中,测试正在为SHA-2 转换做准备,并且涉及空树。

See commit fa26d5e, commit cf02be8, commit 38ee26b, commit 37ab8eb, commit 0370b35, commit 0253e12, commit 45e2ef2, commit 79b0edc, commit 840624f, commit 32a6707, commit 440bf91, commit 0b408ca, commit 2eabd38(28 Oct 2019), and commit 1bcef51, commit ecde49b(05 Oct 2019) by brian m. carlson (bk2204).
(Merged by Junio C Hamano -- gitster--in commit 28014c1, 10 Nov 2019)

提交fa26d5e提交cf02be8提交38ee26b提交37ab8eb提交0370b35提交0253e12提交45e2ef2提交79b0edc提交840624f提交32a6707提交440bf91提交0b408ca提交2eabd38(2019年10月28日),以及提交1bcef51提交ecde49b(2019 年 10 月 5 日)作者:brian m。卡尔森 ( bk2204)
(由Junio C gitsterHamano合并-- --提交 28014c1 中, 2019 年 11 月 10 日)

t/oid-info: add empty tree and empty blob values

Signed-off-by: brian m. carlson

The testsuite will eventually learn how to run using an algorithm other than SHA-1. In preparation for this, teach the test_oidfamily of functions how to look up the empty blob and empty tree values so they can be used.

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

签字人:brian m. 卡尔森

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

So t/oid-info/hash-infonow includes:

所以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

The SHA2 "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321" is the new SHA1 "4b825dc642cb6eb9a060e54bf8d69288fbee4904" empty tree.

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

回答by schimmy

I wrote up a blog post with two different ways of finding the hash: http://colinschimmelfing.com/blog/gits-empty-tree/

我写了一篇博客文章,用两种不同的方式找到哈希:http: //colinschimmelfing.com/blog/gits-empty-tree/

If it were to ever change for some reason, you could use the two ways below to find it. However, I would feel pretty confident using the hash in .bashrc aliases, etc., and I don't think it will change anytime soon.At the very least it would probably be a major release of git.

如果它因某种原因发生变化,您可以使用以下两种方法找到它。但是,我会非常有信心在 .bashrc 别名等中使用哈希,而且我认为它不会很快改变。至少它可能是 git 的一个主要版本。

The two ways are:

这两种方式是:

  1. The answer above: git hash-object -t tree --stdin < /dev/null
  2. Simply initing an empty repo and then running git write-treein that new repo - the hash will be output by git write-tree.
  1. 上面的答案: git hash-object -t tree --stdin < /dev/null
  2. 简单地初始化一个空的 repo,然后git write-tree在那个新的 repo 中运行- 散列将由 git write-tree 输出。

回答by Olleg

Here is the answer on how to create empty tree commit even in the case when the repository is not already empty. https://stackoverflow.com/a/14623458/9361507

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

But I prefer "empty" to be tag, but not a branch. Simple way is:

但我更喜欢“空”作为标签,而不是一个分支。简单的方法是:

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

Because tag can point to tree-ish directly, without commit. Now to get all the files in the working tree:

因为 tag 可以直接指向 tree-ish,无需提交。现在获取工作树中的所有文件:

git diff --name-only empty

Or the same with stat:

或与 stat 相同:

git diff --stat empty

All files as diff:

所有文件作为差异:

git diff empty

Check whitespaces in all files:

检查所有文件中的空格:

git diff --check empty