The main problem with using git checkout HEAD -- .
or git checkout HEAD -- path
is that Git tries to optimize away the checkout, if Git thinks there's no need to do the checkout.1 As you noted in your own answer, git reset
has the same optimization.
There are several ways to defeat the optimization. The one you chose—using git ls-files -z | xargs -0 rm -f
—works fine. Another is to touch
each file that you want Git to overwrite: this invalidates the cache data in Git's index. Since touch
doesn't actually modify the file, this can be simpler: touch *
is usually fairly painless. It doesn't handle subdirectories, though. You could run git ls-files -z | xargs -0 touch
, which is almost the same as in your answer.
1Obviously, if CRLF-handling for index-to-work-tree copying has changed since the previous index-to-work-tree copy step, this optimization is incorrect: Git does need to do the checkout. But Git's cache doesn't realize that. Possibly there should be a plumbing command, git whack-cache
or git frotz-index
or something, that just invalidates each cache entry, so as to force a real checkout.