如果我使用相同的提交哈希,我正在使用 'git log' 的分支是否重要?

Does the branch I'm on using 'git log' matter if I use the same commit hashes?

看哪!我有以下 Git 结构:

A-...-C-D-E      (develop branch)
         \
          X-Y    (feature1 branch)

其中 A、B、C、D 和 E 是开发分支上的提交,X 和 Y 是名为 feature1 的分支上的提交。提交 A 和 C 被未知数量的提交分开。 我们还假设提交 A 具有(部分)提交哈希 b0a710ad5 并且提交 Y 具有(部分)提交哈希 0fc0d3.

现在,有两个有趣的场景。一个我结帐开发和 运行

git log --oneline b0a710ad5..0fc0d3

第二种情况,我改为检查功能 1,并执行相同的命令:

git log --oneline b0a710ad5..0fc0d3

如果我不得不猜测这些场景返回了什么,我会说第一个会给我一个错误,因为开发分支上不存在提交 Y。我猜想第二种情况会给我一个合法的 Git 日志。然而,我大错特错了。我在哪个分支上似乎并不重要:两个命令都给了我完全相同的日志。 git log 似乎可以看到来自其他分支的提交,这是我从未想过的事情

能否git log 在本地存储库的任何分支上找到提交?如果在任何本地分支上都找不到,它是否会远程搜索和查找提交?当我 运行 a git log .. 带有提交哈希值时,我在哪个分支真的不重要吗?哦,可能性。

作为,散列在任何地方都有效。

在大多数情况下,Git 只是使用一个名称来找到 一个散列。也就是说,像 developfeature1 这样的分支名称只是一个人类可读的——重要的是, 可变 ——某些特定哈希 ID 的名称。该哈希 ID 主要是 Git 关心的。像 git log 这样的命令将从名称转换为哈希 ID,然后开始处理提交。提交本身包含另一个哈希 ID,用于其父提交,git log 将查看 that 提交,它有另一个哈希 ID,依此类推。

我们可以 link 以向后的方式向上提交每个提交,使用分支名称查找 last 提交,如下所示:

... <-grandparent <-parent <-0fc0d3   <--branchname

这就是 Git 所做的。

当使用像 b0a710ad5..0fc0d3 这样的范围操作时,Git 直接用于哈希 ID:0fc0d3 是一个 正引用 所以 Git 找到那个提交。由于它们之间有两个点 ..,因此第一个哈希 ID b0a710ad5 在语法上等同于 ^b0a710ad5:它是一个 负引用 。 Git 也找到那个提交,但它使用它来 抑制 显示一些提交。如果 b0a710ad5 本身在链中,Git 在到达 b0a710ad5 时停止 。如果 b0a710ad5 不在 链中——例如,如果提交链看起来更像这样:

    b0a710ad5  ...   <--somename
        /
great-...-grandparent <-... <-parent <-0fc0d3   <--branchname

然后 b0a710ad5 抑制 great-nth-grandparent,Git 通过向后走找到来自 b0a710ad5.

这个从后来的提交开始向后走的过程是 Git 确定提交的 可达性 的方式。如果我们从较晚的提交开始并向后工作并到达较早的提交,则较早的提交 可从较晚的提交(或某个名称)到达

名字有时很重要

请注意,当您进行 new 提交时,通常是在 "on" 某个分支中进行的。 在分支上 意味着 Git 将名称 HEAD 附加到该分支,因此如果我们在右侧绘制带有分支名称的提交,指向提示(最近)提交,其中一个名称附有 HEAD

...--F--G--H   <-- develop
         \
          I--J   <-- feature1 (HEAD)

(这里的单个大写字母代表实际的哈希 ID,它们太笨重了,不用费心。)

如果我们现在进行新提交,Git 将新提交设置为当前提交的哈希 ID J 然后 写入新提交的哈希 ID 改成名字 feature1HEAD 附加到 feature1,并且 feature1 当前命名为提交 J,这就是这一切的工作原理。 Git 进行新提交 K:

...--F--G--H   <-- develop
         \
          I--J   <-- feature1 (HEAD)
              \
               K   [make new commit: parent is HEAD]

然后K写入feature1得到:

...--F--G--H   <-- develop
         \
          I--J
              \
               K   <-- feature1 (HEAD)

我们可以在更少的行上重绘:

...--F--G--H   <-- develop
         \
          I--J--K   <-- feature1 (HEAD)

请注意,在整个操作过程中,HEAD 仍然依附于 feature1feature1 本身会发生变化,以存储新的哈希 ID。

(当您使用 git push 时,您也使用这些名称来标识要发送到其他 Git 存储库的提交。您要求他们设置 他们的 names based on your names. 当你使用 git fetch 时,一些 other Git 存储库的名称是指向具有哈希 ID 的提交,并且您的 Git 复制 提交 ——保持相同的哈希 ID——但随后将新的 origin/* 名称写入 your repository,以便记住 their names 而不会与分支名称冲突。所以名称在这里也很重要——但 hash ID 至少同样重要,因为它们是实际提交的 "true names"。)