When I setup this blog I took the opportunity to try out Git. The thinking was that if I needed to patch the blog software (Mephisto) that I’d have a fairly trouble free upgrade path, merging the upstream changes straight into my branch.
And then, several hours of work later, I lost everything…
I decided to clone the Mephisto code for the 0.8 release from github.com and then made myself a local branch called effectif, in which to make changes for my blog. I’m using Capistrano to deploy the code straight off the effectif branch to my VPS. “Job’s a good ‘un,” (as we say in the UK), but not much to write home about.
Everything was going swimmingly well until I realised that I hadn’t been making my changes relative to the 0.8 release at all—I’d cloned the master branch which isn’t compatible with several Mephisto plugins. Berk!
I considered generating a diff of my changes, pulling a new copy of the 0.8 branch, and just applying the patch. But not for long—this was a great opportunity to learn how to use Git.
Breaking everything (and getting rescued by Git)
I broke everything. Badly.
I ran some obscure and totally inappropriate Git command, and all my changes vanished. By the time I’d finished (randomly) trying to fix it, the HEAD of my branch looked identical to Mephisto 0.8. It was as if all my Capistrano config and theme changes had been erradicated in one fell swoop. Despondency set in. I considered re-doing everything.
Luckily I paused long enough to jump onto the #git channel on irc.freenode.net, where I learnt this little nugget (thanks to a very helpful chap who goes by the name of Eridius).
The reflog command will give you a good history of what’s been happening on the head of your branches. Run it, then find the line that refers to the state that you want to get back to:
$ git reflog
... snip ...
cf42fa2... HEAD@{84}: checkout: moving to master
73b9363... HEAD@{85}: commit: Don't symlink to themes on deployment.
547cc1b... HEAD@{86}: commit: Deploy to effectif.com web server.
1dc3298... HEAD@{87}: commit: Updated the theme.
18c3f51... HEAD@{88}: commit: Verify with Google webmaster tools.
26fbb9c... HEAD@{89}: checkout: moving to effectif
The latest entries appear at the top. You can work out which branch each change was made on by looking out for lines that say “checkout: moving to …”. Lines 88 through to 85 were made on the effectif branch. Change 88 was the earliest, and 85 was the last one before I switched back to the master branch. It was shortly after that that I screwed everything up (you can’t see the logs for that bit), so I needed to revert back to the way things were for commit 85, otherwise known as “73b9363”. Got it? Good, because I’m rather new to this whole Git malarky, and I freely admit that I’m flying blind. Like a bat, only with no sonar.
Anyway, back on topic… All we have to do is make sure that effectif is our current branch (this bit is important, or you could end nuking changes on another branch), then reset it to the correct state:
git checkout effectif
git reset --hard 73b9363
The --hard option makes sure that all files (including those with local modifications) are reverted to the commit specified. Have a poke around the git-reset(1) man page for other options. It’s like time travel, only cheaper.
Switching to the correct branch with git
Now this is the incredible bit (apologies if you’ve been holding out all this time for some “incredible merging”—I hope it was worth the wait). I made my changes when the effectif branch was based on master, though it should have been branched from rel-0.8. This rebase command puts all the changes that I applied to one side, updates the effectif branch as if it had been branched from rel-0.8 in the first place, and then re-applies my local changes (read that description again; it’s mega):
git rebase --onto rel-0.8 master
It worked perfectly, and I’m still slightly amazed about it.