为什么 git 的预提交挂钩会验证 HEAD 是否存在?

Why does git's pre-commit hook verify that HEAD exists?

在它的预提交挂钩中 git 似乎验证了 HEAD 存在。如果不是,它默认为一个空树的特殊散列来与索引进行比较。

if git rev-parse --verify HEAD >/dev/null 2>&1
then
        against=HEAD
else
        # Initial commit: diff against an empty tree object
        against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

它默认的散列是一个特殊的散列。我读到我也可以通过

获得它
git hash-object -t tree < /dev/null

against以后是这样用的

# If there are whitespace errors, print the offending file names and fail.
exec git diff-index --check --cached $against --

为什么钩子会那样做?在什么情况下我可以提交但 HEAD 无效?

HEAD 总是指向当前提交,因为:

  • 它包含当前分支的名称(例如ref: refs/heads/master),或
  • 它直接指向实际的提交 ID("detached HEAD"),因此它包含一个原始的 SHA-1 哈希字符串。

如果 HEAD 包含原始哈希值,那么 HEAD 绝对有效,因为它必须指向真正的提交。但是...在一个全新的空存储库中会发生什么?

您在分支 master,因此 HEAD 读取 ref: refs/heads/master。但是分支 master 的尖端是什么?什么提交 ID 存储在 master 本身?

存储库中没有提交。 master 点在哪里?

Git解决这个问题的方法是让master保持无效。那是 git rev-parse --verify HEAD 失败的时候:HEADmaster,但是 master 还不存在。

在内部,Git 将其称为 "unborn branch",有时也称为 "orphan branch"。使用 git checkout --orphan newbranch 将 Git 置于新创建的相同状态(除了它尚未真正创建 尚未 )分支 newbranchHEAD 引用现在包含 ref: refs/heads/newbranch,但仍然没有 newbranch。所以每个未出生的分支状态都是这样的,但是每次创建一个新的空存储库时都会看到一个特定的状态。