git reflog show origin/master
shows even remote forced-updates. So although it looked like the commit was lost, it was still there, just not immediately visible, and was fully recoverable.It'd be amazing if GitHub began exposing reflogs through the web somehow.
(I <3 git.)
The other developer had several recourses.
The awesome ProGIT book: http://progit.org/
The hotness of the GitReady: http://gitready.com/
The great MAN pages of course: http://www.kernel.org/pub/software/scm/git/docs/
GitCasting like a boss: http://gitcasts.com/
GIT users on IRC: irc://freenode.net/git
And of course, Github itself. They're awesome in a box: http://help.github.com/
Regardless, it's nice to see a developer publicly admit the error of his ways, and even nicer to see other developers brush it off and keep going as they give support.
-f, --force
Usually, the command refuses to update a remote ref that is not an
ancestor of the local ref used to overwrite it. This flag disables
the check. This can cause the remote repository to lose commits;
use it with care.
And even with that, the commit wasn't lost yet. It likely in the reflog of the remote repo, and in the history of whichever repo the change was originally pushed from.That said, there are ways to lose work with git that aren't recoverable ("reset --hard" silently overwrites uncommitted work), but this isn't one of them.
Which git sort-of does (reflog). And then, after it prevented you from shooting yourself into the foot, it gives you a loaded Howitzer pointed at your face. (git reflog expire/git prune/git gc)
I love git dearly, but that's still a large flaw in its design. There is no reason to ever lose history.
Git uses local, cloned repositories and users can do everything they like with them. Changes can be pushed and pulled to other repositories, possibly changing them irreversibly.
By using github you use GIT in a (kind of) centralized way. Suddenly there is an 'central project repository' again, that needs to be protected against damage. But as GIT was never meant to do this, and trusts its users, it has to be bolted on somehow... at least, that's how I understand it.
I hope they will get this right as it's very important for accountability.
The -f should mean "don't do this, it will probably wreck your shit". Unfortunately certain tools seem to require it way too often so it seems to be going the way of the venerable confirm dialog.
"Deleted all my files? I dunno, some funny box popped up and I hit OK. Was that it?"
For example, the developer who overwrote the commits in the case in question probably did so after seeing the following error message:
abort: push creates new remote heads on branch 'default'!
(did you forget to merge? use push -f to force)
While it mentions merging, the only recognizable command line ("push -f") is for a destructive operation, instead of the operation (pull or merge, depending on the situation) that will actually fix the unsafe condition. Putting an even partial command line in front of a developer is like putting an OK button in front of a non-technical user - they tend to just use it to see if it (superficially) works. When it (subtly) fails, a novice user will not notice, and will just remember "push -f" as the Right Way to Use Git.The git version is:
$ git push github master
To git@gitproxy:rip747/ cfwheels.git
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to ‘git@gitproxy:rip747/cfwheels.git’
That makes no mention of -f (or any git commands at all).Of course, somebody still has to know and care enough to want to tweak the default configuration, and it doesn't help with GitHub for the moment, but I wouldn't be surprised if they added finer-grained branch permissions in future.