Sure, maybe the data was actually there and a git god could have unwound whatever brain damaged state "git push" stuck the repo in. Maybe. However, it's not like everybody didn't try. The only thing that saved them was that I take snapshots of git repositories via rsync every hour because I know this is going to happen. Not might--will.
I have never had this happen with Mercurial. Ever. I don't even think about it. I wouldn't dream of rsync'ing a Mercurial repository because I've never put a repo in a state that I can't find the data.
Everybody apologizes for git. I don't have to apologize for Mercurial.
! [rejected] master -> master (non-fast-forward)
# error: failed to push some refs to 'https://github.com/
USERNAME/REPOSITORY.git'
# To prevent you from losing history, non-fast-forward updates were rejected
# Merge the remote changes (e.g. 'git pull') before pushing again. See the
# 'Note about fast-forwards' section of 'git push --help' for details.> Dude, this is NOT theory. I watched it happen.
No, you thought you saw it happen. "git push" does not remove data, it can only add new commits (and their contents) and update refs (branch names and tags) so you were mistaken in what you saw.
> Sure, maybe the data was actually there
Yup, exactly. No data was lost. It was actually there.
> and a git god could have unwound whatever brain damaged state "git push" stuck the repo in
I like the "git god" moniker. Thanks! But it's not really that complicated. What probably happened was that "git push" added a new line of commits, and updated your branch name (let's say it was "master") to point at these new ones. The old ones were still there though, they just weren't an ancestor of your current "master" so you couldn't see them immediately with "git log".
If you wanted to get your repository back to its previous state, you just needed to look with "git reflog" and see what commit master used to point to, and then set it back to that. That's the only change you needed to make. The repository wasn't broken in any way, it just had a few more commits in it.
Now, you might say that "git push" shouldn't make it so easy to do this: and you'd be right, so it doesn't. You need to have used "--force" to get it to behave in this way. Really, if this is a happening regularly, you clearly have a broken workflow. Perhaps introducing some Code Review in there would help? Gerrit maybe?
Also, a "third or fourth year course in CS" is not a prerequisite for understanding git. I am proof of that :-)