问题描述
我在 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
链接:https://www.atlassian.com/git/tutorials/resetting-checking-out-and-reverting
部分:“Git Checkout 文件”
起初工作目录是干净的:
On branch master
nothing to commit,working tree clean
现在我修改test.txt
,现在运行git add
和git 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
根据文档,index 中 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 的官方文档:
覆盖与路径规范匹配的文件的内容。当。。。的时候
<tree-ish>
(最常见的是提交)未给出,覆盖工作树
与索引中的内容。当给出 <tree-ish>
时,
用位于的内容覆盖索引和工作树
<tree-ish>
。
您处于第二种情况,其中给出了 <tree-ish>
(HEAD
),这是预期的行为:索引和工作目录都被旧版本的 {{1} }.
相反,如果您使用 test.txt
,并且 git checkout test.txt
已经暂存,则工作目录或索引都不会更改,因为您基本上是将工作目录版本替换为索引版本,但显然是一样。
Atlassian 文章想说的是:
-
test.txt
主要对工作目录进行操作(如果提供了git checkout <pathspec>
,也会对索引进行操作) -
<tree-ish>
仅对索引进行操作。
产生误解是因为在 git reset
中 git reset
默认为 <tree-ish>
。相反,如果您指定 HEAD
,git checkout
的行为会有所不同。