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...
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.
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(+)
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).
The odd-looking command in the middle, git push origin :
, 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).
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™.