Take Control of Your Commit History

Constructing clean commit histories just got a lot easier with Git Poooosh.

I review projects’ commit histories pretty frequently. What can I say? I’m an overzealous older brother always looking to improve myself and the teammates around me. I watch projects progress, looking back to see how features and implementations have evolved. As a team, we also use Github’s compare feature in incremental release notes to our clients to keep ourselves accountable, ease integrations, and educate our clients.

So, let's compare commit histories in chruby and rails...

1DBt5Hm

Looking at the commit history of chruby (on the left), it’s pretty clear what’s happening from commit to commit. Without too much digging, you can get a quick understanding of the changes that went into the first revision of v0.3. Rails commit history (on the right), on the other hand, is a little more challenging.

The difference is hidden in those pesky Merge pull request #17881 from awesome-contributor/cool-new-feature commits created by Github’s big green Merge Pull Request button. Others have voiced their hearty opinions about the Big Green History Crusher™ and though I tend to agree, I’d rather share an alternative for merging pull requests that leaves behind a helpful commit history for collaboration, code review, and diagnosis.

Caveat

Everything I’m about to share assumes you’ve followed the wise words of Rob and Adam by Creating Good Pull Requests and completed a solid Code Review.

Git Square

In almost every case, we’re collaborating by pushing and pulling against a central Github repository—the Hub and Spoke model. To get square, we would git pull --rebase while in master. Some prefer to use git-up for this, but I have an alias that’s less magical. The --rebase assures that any commits I alone have are reapplied atop those coming from origin. In most cases, nothing like this happens, but I’m always relieved when it does.

Once master is up to speed, we rebase our PR branch with git rebase master. We rebase our PR branch for the same reason we used --rebase: we want to ensure that our changes are reapplied on top of any changes already integrated into origin/master (the Hub of our collaboration).

Git Fast Forward

This is the key to beautiful history. Put simply, we likely want master to look like the branch underlying this pull request. If only we could just point master at that last commit in fancy-feature-branch. Well, we can:

$> git merge --ff-only fancy-feature-branch
Updating 020fbbd..0d154e9
Fast-forward
README.md | 2 ++
1 file changed, 2 insertions(+)
view raw git-merge-ff-only.sh hosted with ❤ by GitHub

Since we were good contributors and rebased the feature branch, we didn’t really need the --ff-only option. By including this flag, though, we’re telling git we want this to fail if it’s not a fast forward. Coincidentally, this is the complete opposite of what the Big Green History Crusher™ invokes. That will give us a merge commit every time—even if it wasn’t necessary.

Git Push

At this point, we’ve merged in the pull request locally, rerun our tests because we’ve been embarrassed too many times, and we’re ready to close things out with a git push. And that’s all you really have to do. Except then we would have stale branches locally and on origin. Wouldn’t it be nice if we could push our merged pull request and clean it up in one go?

Surprise! We can:

$> git push && git push origin :fancy-feature-branch && git branch -d fancy-feature-branch
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:cromwellryan/dotfiles
020fbbd..0d154e9 master -> master
To git@github.com:cromwellryan/dotfiles
- [deleted] fancy-feature-branch
Deleted branch fancy-feature-branch (was 0d154e9).
view raw git-poooosh.sh hosted with ❤ by GitHub

The odd-looking command in the middle, git push origin :<branch-name>, will delete a remote branch. That’s a tall order for a simple colon, but it’s incredibly convenient. Heck, if you follow our Git Commit Style Guide, you can even close issues automatically!

Git Poooosh

That’s an awful lot of typing compared to clicking a Big Green Button™. Luckily, we have robots to do boring things for us. That’s why I’ve created Git-Poooosh.

Git-Poooosh is a plugin for oh-my-zsh that will push the current branch and delete the remote and local feature branches, with branch autocomplete. Simply drop the git-poooosh directory into ~/.oh-my-zsh/custom/plugins, add it to your .zshrc plugins, and restart your shell. Now that monstrous last step looks like this:

$> gpp fancy-feature-branch
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:cromwellryan/dotfiles
020fbbd..0d154e9 master -> master
To git@github.com:cromwellryan/dotfiles
- [deleted] fancy-feature-branch
Deleted branch fancy-feature-branch (was 0d154e9).
view raw gpp.sh hosted with ❤ by GitHub

 

Git Poosh Commands

Take Control

It can be very easy to take source control and commit history for granted, writing it off as a necessary evil. From more effective pull requests to locating changes in the past, a few subtle changes in your git workflow can help you take back control of your commit history from the Big Green History Crusher™.