So a partial retraction to my previous post…
It turns out that git has something called a reflog, which seems to be purely documented in the git-reflog(1) manpage, and to my taste, rather tersely. It appears that git does keep at least a partial log of recent operations so it’s possible, with varying degrees of success, to undo past operations. Or at least this was the theory I read scattered across several bits of oral tradition like personal webpages and blogs and what I could glean from the manpage.
I didn’t see any commands to actually recover data from the reflog, only to read what’s in it. Regardless, at least I was able to recover a few of the branches that git deleted remotely and from reading the commit messages, which I hadn’t noticed before, I was able to guess where the remaining accidentally deleted branches were.
So, anyways, git does have a recovery mechanism… somewhat… It’s about the same way that it’s still possible with some luck do an undelete on an ext3 filesystem. In other aspects, git is still too complicated and dangerous for my taste. It’s a little funny because I’m actually quite comfortable with complicated and dangerous tools elsewhere, like good ol’ rm, cp, mv and other dangerous Unix tools where a typo can mean instant data loss. I recognise that perhaps there should be better ways to do this, but I don’t know of one I like. In the case of VCSes, I know of a better, simpler, safer tool than git, and it’s hg. Perhaps it’s because I have an alternative and feel proficient with it that I prefer it to git.
I will use git again, very cautiously. It’s not a VCS where I can experiment widely without fear, because git erases data remotely. It’s however unavoidable due to its popularity, and I will need to acquire some fluency with it if I’m to keep collaborating with people who use git. For my personal use, I don’t see myself moving away from hg for quite some time to come.
3 thoughts on “I don’t hate git as much anymore…”
Bear in mind that the reflog is NOT transmitted when you push to a remote location, and it is garbage collected, by default, after 30 days. So you’d better make sure that you never throw away any copies of repositories AND you correct any problems within the gc window or else you’re seriously out of luck.
Or, just use a better VCS.
After reading this blog entry I decided to try using reflog to recover from a simulated “push –mirror” mishap. Using a recent version of git (2.20.1, packaged in Debian 10) I found that, contrary to what I’ve been told, neither the local reflog nor the remote reflog included any reference to the orphaned commits. “git reflog” was useless.
I did find that in _some_ scenarios the terminal scrollback buffer included a reference that allowed me to effect a recovery. Advice to anyone who suffers this mishap in the future: preserve your terminal scrollback buffer!
In the first and simplest scenario that I tried (pasted below) there are no branches other than master. Bob has accidentally destroyed Alice’s commit to master, and Alice’s laptop is not available. “git reflog” is useless (try it yourself, and see). It’s possible to recover by using Bob’s terminal scrollback buffer, but without that buffer I’m not aware of any way to recover, short of running fsck and just _guessing_ which branch, if any, each unreferenced commit was supposed to belong to.
I ran these commands in a new user account, with no git settings configured except user.name and user.email.
mkdir shared.git; cd shared.git; git init –bare; cd ..; git clone shared.git aliceclone; git clone shared.git bobclone; cd aliceclone; echo 16,053,920,967,346,445,229 > important.txt; git add .; git commit -m important; git push; cd ..; rm -rf aliceclone; cd bobclone; echo x > x.txt; git add .; git commit -m x; git push –mirror
Each of those en-dash characters (unicode U+2013) is actually supposed to be two hyphen-minus characters (U+002D). The blog software changed them.