「这是我参与11月更文挑战的第 12 天,活动详情查看:2021最后一次更文挑战」
提交在哪
几乎所有的 git 命令都需要知道当前准备提交是什么。例如,git commit
需要知道当前的提交在哪,因为它将成为马上新提交的父本。
举个例子,在我某一个仓库中,我们正处于 af64eba
提交。git 是怎么知道的?
你可能知道 HEAD 可以用来指代当前的提交。
例如,git show HEAD
显示了当前提交的提交信息和它所引入的修改。所有的 git 状态都存储在 .git
目录中,这包括告诉我们当前位置的文件:.git/HEAD
。
写段代码,让我们看一下它的内容。(注意:这些例子使用同步I/O,以便关注git内部。有很多机会可以并行地执行文件系统操作,所以使用异步I/O可以显著提高性能)
1 | rust复制代码use std::fs; |
运行该代码,会得到以下结果:
1 | swift复制代码Head file: "ref: refs/heads/main\n" |
.git/HEAD
文件结果告诉我们,我们已经切出了主分支。
这是我们想知道的部分内容,但我们仍然没有弄清楚git如何知道main指的是什么提交。
事实证明,refs/heads/main 实际上是.git目录下一个文件的名字。来读读它的内容:
1 | rust复制代码use std::path::Path; |
结果显示:
1 | rust复制代码main: "af64eba00e3cfccc058403c4a110bb49b938af2f\n" |
如果你还记得,我们创建的提交被称为:af64eba
,.git/refs/heads/main
以这些十六进制数字开头并不是巧合。
这个由40个十六进制数字(代表20个字节)组成的完整字符串被称为 “提交hash”。
我们很快就会看到它是如何计算的(以及它为什么被称为 “hash”),但现在你可以把它看作是提交文件的唯一标识符。
check out
操作也有可能(虽然不太常见)切出一个特定的提交,而不是一个分支。例如,我们可以运行 git checkout af64eba
来切出当前的提交。
1 | rust复制代码Note: switching to 'af64eba'. |
在这种情况下,.git/HEAD文件会直接指定提交hash:
1 | rust复制代码Head file: "af64eba00e3cfccc058403c4a110bb49b938af2f\n" |
本文转载自: 掘金