How I Git
I'll bet you use git (or Subversion or something, but I know git so that's what I'm writing about). This post may be review for you, but I have opinions and I want to share them on the internet! Jason McCreary wrote some posts about git including this one which sums up git rebase
better than I care to. Check it out.
Why do we use git; what problem are we trying to solve?
- Revert - You want to be able to confidently undo changes that break your code.
- Track changes - You want to be able to figure out what was necessary to implement a feature, or how various code is related to other code. Mostly, you want to know why somebody chose to write a particular piece of code.
There are obviously lots of other great features, but these two will suffice for the purposes of this post.
Formative Moments
I made two very memorable mistakes with git in my first few months as a software developer.
The first related to a feature I had been working on for several days. I was in the habit of making fairly atomic commits along with WIP (Work In Progress) commits at the end of the day. I'm not sure where my pair was when this went down, but at some point, I ended up merging my branch into master and pushing. Within half an hour or so, a chat room blew up with questions about merge commits and WIP commits in master. I was terribly embarrassed, but another developer helped explain what I should have done (squash and rebase).
The second offense was worse. I had pushed code to master that broke something. Upon seeing this, I immediately knew what the problem was and decided to fix it. My solution was to fix the tests and code, amend
the commit, and (force) push back to master. This process took maybe five minutes and I figured nobody would be the wiser. Of course the chat quickly blew up again. This time somebody was wondering why they were unable to push to master, having rebased minutes before. Again, I had to identify myself as the culprit.
These were dumb things in retrospect, but you can bet that I learned my lesson. Don't be like me. Follow best practices and your colleagues won't hate you.
Some best-practices
Imagine you're working on a feature branch and are ready to submit a PR or however you prefer to submit your code for review.
rebase
to keep your branch up to date. This is helpful to do frequently while working on a branch to ensure you have the latest commits from master. Make sure you do it before creating a PR or merging into master. I almost always complain when I see a PR for a branch that is "3 commits ahead and 30 commits behind" master*.- Squash many of your commits. This one is slightly contentious, but need not be. Remember that the whole point of your commits is to tell a coherent story (and be able to easily revert if something goes wrong). That means that commits destined for master should not have WIP in them and should not include stuff like "fixed more typos." Keep track of that stuff however you want when working on a branch, but squash them before the make it to master.** I like to squash through an interactive rebase. On the off chance that you do need to revert a commit, having one commit per feature will ensure that you can revert the whole thing without breaking master or dealing with merge commits.
- 50/72: Message is 50 chars, description wraps at 72 - Here is one of about a thousand blog posts on why the 50/72 rule of git commits makes sense. Lots of tooling is built around commit messages looking a certain way. It's built into my tooling so I don't even have to think about it. One important side note here is that you should really add comments to commits. There is plenty of room to explain why you made certain choices or any other useful context.
- Get your gross merge commits out of my master branch. If you follow the previous points then your PR will be neat and tidy and ahead of master. There is no reason for a merge commit. If you're using Github then you can just "Rebase and Merge" or if you're going cowboy-style then you can just merge your branch into master. Get that:
git merge my-branch
won't even create a merge commit. It's like git telling you that you're doing it right.
Finally
“Code needs to work today just once, but needs to be easy to change forever.” -Sandi Metz
The audience for your git commit history, like your code itself, is your future self and your future colleagues. Make it easy on them. These suggestions may seem petty and annoying at first, but are really pretty easy to get used to. The benefits far outweigh any cost. Alias git blame
to git praise
if you have to.
* An unnamed collaborator on a project once merged (his own) PR that was in this 3 ahead, 30 behind state. He ended up merging in some commit from weeks before that broke production and was a nightmare to track down. Don't be "him."
** Sometimes people think that they need to track every single commit, change, and dead end as a way of "telling the truth" or preserving context. I argue that a clean commit history (before changes make it to master) tells a better story. If you are worried about preserving context for decisions, then spend some extra time on the commit message and tell that story explicitly. Now, once a commit is in master then the "telling the truth" argument makes sense.