I've come across this statement in git documentation:
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
Section: "Git Checkout File"
Now suppose I have a repo and a file test.txt
in it
At first the working directory is clean:
On branch master
nothing to commit, working tree clean
Now I modify test.txt
, run git add
and git status
shows now:
On branch master
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: test.txt
Now I run git checkout HEAD test.txt
and get:
Updated 1 path from 58e7043
Output of git status
:
On branch master
nothing to commit, working tree clean
According to the docs the version of test.txt
in the index should have stayed the same and the version of it in the working directory should've changed back to its version in the commit to which HEAD points, resulting in different versions of the file between the working directory and the index --> in which case shouldn't git status
output something ? But git status
doesn't show that - why ?
Usually to go from staged file to clean working tree I'd have to use git reset HEAD <filename>
followed by git checkout HEAD <filename>
for that file but here it seems to do both ??
I'm confused
Edit - also what's interesting is that if after staging the file test.txt
I run git checkout test.txt
instead of git checkout HEAD test.txt
I get:
Updated 0 paths from the index
Even though these 2 forms should be equivalent where the former defaults to HEAD
as well (?)
I'm confused again
First of all, that is not the official documentation and this is a case, in my opinion, where Atlassian is very superficial on the comparison between the two commands. Sometimes, like this time, the same git command does very different operations depending on which options you use. On SO you can find good answers that go deep into the topic.
Just to answer to your question, here is what the official documentation says about 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>
.
You are in the second case, where the <tree-ish>
is given (HEAD
) and that is the expected behaviour: both the index and working directory are overwritten with the old version of test.txt
.
Instead, if you use git checkout test.txt
, and test.txt
is already staged, neither the working dir or the index change because you are basically replacing the working dir version with the index version, but are obviously the same.
What Atlassian article is trying to say is that:
git checkout <pathspec>
operates on the working dir mainly (on the index too if a <tree-ish>
is provided)git reset
operates on the index only.The misunderstanding has arisen because in git reset
the <tree-ish>
defaults to HEAD
. Instead, git checkout
behaves differently if you specify a <tree-ish>
or not.