The Meat Cleaver That Cuts: Git Rebase

While I’ve been writing my Git book, I keep trying to pick up new tricks and figure out places to use them. A came across a post on git rebase --interactive and knew I had to find an opportunity to play with this. This morning, that opportunity came.

I’ve been working on some performance enhancement at work this week. I use Git locally for all of my development, then push back to our central Subversion repo once my changes are done and approved for the main repository. Timing for the changes I made earlier in the week was bad, so I was going to hang on to them for a week and push them when our engineering/QA department can absorb them more easily.

… the observant reader should be picking up on the past-tense here …

So as part of my changes I created a Registry to share a single instance of an object around instead of going the Singleton route or putting the data in the global scope. Pretty useful all round, but silly me didn’t think to put that in a branch by itself so I could pull that change around as necessary. No worries.

Light Bulb! “Ah ha! I’ll just switch into my branch and use git rebase --interactive to rewrite all of those commits and squash them together. A quick git cherry-pick later and I’ll have my Registry object in this new branch on some other functionality I’m working on.”

If you’ve ever used git rebase you can probably see where this is going. If you haven’t, it’s probably one of the more dangerous commands—if not the most—in Git. It will literally let you reshape the history of the repository. Running with scissors is child’s play. No, rebase can really screw you over. Imagine riding a unicycle while juggling four meat cleavers and you’ll have the idea. Really, and I mean really impressive to watch, but one false move and you’re screwed.

So back to my experience. I proceeded to weed through the 80 or so commits from Monday afternoon and Tuesday morning and pull out everything that didn’t relate to the code I wanted. “Git will just ignore those” I naively thought. I got it down to the 8 or so commits that had to do with my registry object and its tests and squashed them all into one commit. I knew I was rewriting the history, but it never occurred to me that I was rewriting history. I let rebase do its thing, then cherry-pick‘d my newly created revision and was off.

Until this afternoon. Rumor of my changes had made it around the office and someone else wanted to see them. Since I only track our trunk and not all of our branches and I’m the only there using Git, the easiest solution was to just create a patch to send to him. Simple enough. Use git merge --squash and git diff --no-prefix --cached and I’d have a patch he could apply directly to his copy and we’re set.

Needless to say, when I started reviewing the patch, I notice there was a lot missing. :-(

Lesson learned. Don’t play with live data when trying new stuff out. When you miss a bean bag while you’re juggling, you don’t loose your toe…