Git maintains what's called a "reflog" to help with this. It's a record of every place that every ref has ever pointed in your repository. Try it: `git reflog master`. You can even see when you did pulls, and what they merged in.
The only truly destructive thing you can do to your git database is `git gc`.
And of course we should expect garbage collection to be destructive of information that is not garbage?
Didn't know that? Just read the man page. Whoops, it doesn't actually mention that, but it does mention that it may happen automatically at times.
So only clever people like you know archaic undocumented side effects of git's inscrutable design, except nobody ever really knows the full story because there is so much unnecessary crud to learn in addition. Clearly more can be destructive than gc if gc can be executed by other commands and triggers by repository state.
I do not think one can do this accidentally:
git gc --prune=2012-08-05
In practice however, I've found a force push can be useful. For example, we once had a dev push code to our deployment branch which wasn't in fact ready for production. We could have just reverted all the commits which were added, but this would be messy and make merging again later painful. Instead, just `git reset --hard` to before the merge and force push.
If you understand the implications of rebase and force push, you shouldn't have to worry about losing data.