为什么 git 检出文件的行为类似于重置暂存文件,然后检出未暂存文件?

Why does git checkout file behave like reset staged file followed by checkout unstaged file?

我在 git 文档中看到过这个声明:

Checking out a file is similar to using git reset with a file path, except it updates the working directory instead of the stage

Link:https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting

部分:“Git 签出文件”

现在假设我有一个 repo 和一个文件 test.txt

起初工作目录是干净的:

On branch master
nothing to commit, working tree clean

现在我修改 test.txt, 运行 git addgit status 现在显示:

On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        modified:   test.txt

现在我 运行 git checkout HEAD test.txt 得到:

Updated 1 path from 58e7043

git status 的输出:

On branch master
nothing to commit, working tree clean

根据文档,索引test.txt的版本应该保持不变及其版本在工作目录中应该在 HEAD 指向的提交中改回其版本,导致工作目录和索引之间的文件版本不同 --> 在这种情况下git status 不应该输出一些东西吗?但是 git status 没有显示 - 为什么?

通常要从暂存文件转到清理工作树,我必须使用 git reset HEAD <filename> 后跟 git checkout HEAD <filename> 作为该文件,但 此处似乎两者都做 ??

我很困惑

编辑 - 同样有趣的是,如果在暂存文件后 test.txt 我 运行 git checkout test.txt 而不是 git checkout HEAD test.txt 我得到:

Updated 0 paths from the index

即使这两种形式应该是等价的,前者也默认为 HEAD (?)

我又糊涂了

首先,这不是官方文档,在我看来,Atlassian 对这两个命令的比较非常肤浅。 有时,就像这次一样,相同的 git 命令会根据您使用的选项执行截然不同的操作。在 SO 上,您可以找到深入主题的好答案。

为了回答你的问题,官方文档是这样说的 git checkout with a pathspec:

Overwrite the contents of the files that match the pathspec. When the <tree-ish> (most often a commit) is not given, overwrite working tree with the contents in the index. When the <tree-ish> is given, overwrite both the index and the working tree with the contents at the <tree-ish>.

您处于第二种情况,其中给出了 <tree-ish> (HEAD),这是预期的行为:索引和工作目录都被旧版本的 [= 覆盖16=].

相反,如果您使用 git checkout test.txt,并且 test.txt 已经上演,工作目录或索引都不会改变,因为您基本上是用索引版本替换工作目录版本,但是明明是一样的

Atlassian 文章想表达的是:

  • git checkout <pathspec> 主要在工作目录上运行(如果提供了 <tree-ish>,也会在索引上运行)
  • git reset 仅对索引进行操作。

产生误解是因为在git reset<tree-ish>默认为HEAD。相反,如果您指定 <tree-ish> 或不指定 git checkout,则 git checkout 的行为会有所不同。