git reset --hard HEAD leaves untracked files behind

git reset --hard && git clean -df

or, zsh provides a 'gpristine' alias:

alias gpristine='git reset --hard && git clean -df'

Which is really handy.

Optional:

There is also an -x option for the git clean command. Which will also delete 'git ignored' files, so add this option as well if it is what you want.

If working on a forked repo, make sure to fetch and reset from the correct repo/branch, for example:

git fetch upstream && git reset --hard upstream/master && git clean -df

You have to use git clean -f -d to get rid of untracked files and directories in your working copy. You can add -x to also remove ignored files, more info on that in this excellent SO answer.

If you need to reset an entire repository with submodules to the state on master, run this script:

git fetch origin master
git checkout --force -B master origin/master
git reset --hard
git clean -fdx
git submodule update --init --recursive --force
git submodule foreach git fetch
git submodule foreach git checkout --force -B master origin/master
git submodule foreach git reset --hard
git submodule foreach git clean -fdx

If you have files you still want to keep:

git clean -di will do an interactive clean which allows you to only delete the files/dirs you don't want anymore.

Tags:

Git