The last three commits (HEAD, HEAD^, and HEAD~2) were bad
and you do not want to ever see them again. Do not do this if
you have already given these commits to somebody else. (See the
"RECOVERING FROM UPSTREAM REBASE" section in git-rebase(1) for
the implications of doing so.)

You are happily working on something, and find the changes
in these files are in good order. You do not want to see them
when you run "git diff", because you plan to work on other files
and changes with these files are distracting.

Somebody asks you to pull, and the changes sounds worthy of merging.

However, you already dirtied the index (i.e. your index does
not match the HEAD commit). But you know the pull you are going
to make does not affect frotz.c nor filfre.c, so you revert the
index changes for these two files. Your changes in working tree
remain there.

Then you can pull and merge, leaving frotz.c and filfre.c
changes still in the working tree.

Try to update from the upstream resulted in a lot of
conflicts; you were not ready to spend a lot of time merging
right now, so you decide to do that later.

"pull" has not made merge commit, so "git reset --hard"
which is a synonym for "git reset --hard HEAD" clears the mess
from the index file and the working tree.

Merge a topic branch into the current branch, which resulted
in a fast forward.

But you decided that the topic branch is not ready for public
consumption yet. "pull" or "merge" always leaves the original
tip of the current branch in ORIG_HEAD, so resetting hard to it
brings your index file and the working tree back to that state,
and resets the tip of the branch to that commit.

Even if you may have local modifications in your
working tree, you can safely say "git pull" when you know
that the change in the other branch does not overlap with
them.

After inspecting the result of the merge, you may find
that the change in the other branch is unsatisfactory. Running
"git reset --hard ORIG_HEAD" will let you go back to where you
were, but it will discard your local changes, which you do not
want. "git reset --merge" keeps your local changes.

Interrupted workflow

Suppose you are interrupted by an urgent fix request while you
are in the middle of a large change. The files in your
working tree are not in any shape to be committed yet, but you
need to get to the other branch for a quick bugfix.