This all has to do with Git's index.
The index has several functions in Git, but the main one is that it's where you build the next commit. Other version control systems don't have a separate index (or completely hide it from you): they have just the current commit, which is the obvious thing and which Git calls HEAD, and the work-tree, which is where you can see and edit your files. But Git has this extra, third thing.
This third thing, this index, is why you must git add
changes you make. Until you git add
your new version of some work-tree file, the index version still matches the one in the HEAD commit. So the next commit you will make won't have the new version of the file in it yet.
The command:
git checkout -- .
copies files from the index, to the work-tree. If you have not git add
ed the updated versions, the index versions match the HEAD commit, so this copies the same version as the HEAD commit, to the work-tree.
The command:
git checkout <revision> -- .
however, does something very different: it copies everything from the specified revision into the index, and then copies those files from the index into the work-tree. Now that the index version of each file is changed:
git checkout -- .
just gets those same index versions into your work-tree again. They're all still ready to commit in a new commit, too.
You can:
git checkout HEAD -- .
which will copy all the files from the HEAD commit into the index and on into the work-tree. This will make HEAD, index, and work-tree all match again.
Meanwhile, the command:
git reset --hard HEAD
is a little bit different, but has the same effect in the end: first, it moves the current branch from HEAD
to HEAD
. Since this doesn't move it anywhere, that has no effect at all. Next, it copies the new HEAD's files into the index, and last, it copies those files from the index to the work-tree (this is the --hard
step).
There are some additional differences that you could see if you had new files in the index, that were not in the HEAD
commit. Using git checkout HEAD -- .
would leave them in there, while git reset --hard HEAD
would remove them (from index and work-tree both).