Simplify writing code with deliberate commits

Do you ever find yourself juggling an ever growing list of things to think about when you are working on a feature? Do you find yourself losing track of what needs to be done next to make progress? If you do (and, spoiler, we all do), then this is the talk for you.

One tool that we under use to help us keep focused and keep our work simple is our source control system. In this talk I will outline some habits and practical techniques to apply to your local development workflow with git that can help simplify the development of software in complex, real world environments and make you a better software developer. These include

  1. Planning your commits
  2. Making atomic commits
  3. Writing commit messages that provide context to your decisions
  4. Ensuring that each of your development branches has a single purpose
  5. Regularly using git rebase --interactive to ensure your development branches tell a clear story about the work that you are doing

A neat side effect of these approaches is that they will give you the added bonus of well documented code that is easier for your colleagues to review and/or make sense of in future

📄 Transcript

This transcript is from a version of the talk I gave at Frontend London in May 2019.

Slide 001
I’m here to talk about commit practices.
Slide 002
I am Joel Chippindale. I work at Unmade as the CTO and have been leading software development teams for the last 15 years. Most of my job there is helping teams be effective and develop their skills and today I will be sharing some habits and practices which will hopefully be helpful to you.
Slide 003

I want to start with a quote, “If you can’t explain it simply you don’t understand it well enough”. This is often attributed to Albert Einstein.

It may not have been said by him but I think he would have meant it. He was talking about physics, if he said it, but I think it applies equally well to our jobs and the code we write. If we can’t explain our code simply then we don’t understand it well enough.

Slide 004

There was a huge change for me in how I developed software when I started using git, over a decade ago.

The flexibility it offered in terms of how you can play with commits, create branches easily, merge commits, split commits up, amend commits, changed the way that I thought about using my version control system.

Before that it was just a place to keep all the old versions of my code, which is great, better than just renaming files in directories which I had been doing beforehand but now it was a tool which helped me understand the work I was doing. I want to share with you some of the practices that helped with that.

Slide 005

Image courtesy of Wikinaut (CC BY-SA)

We all work on complex systems and I think that this makes us very lucky in that it means our jobs are interesting but it means we are dealing with complexity every day.
Slide 006
We learn, in our roles, to manage that complexity by breaking things down into small simple changes and that’s a really important skill for all of us.
Slide 007

Image courtesy of WOCinTech Chat (CC BY)

The best developers I have ever worked with are all really good at this and perhaps it is the defining characteristic of a really good developer.
Slide 008
This is hard but we can all learn to get better and get better in our jobs.
Slide 009

It is also problematic because it takes discipline and willpower, which takes up space in our heads, for a few good reasons.

Firstly we are all optimists. Some of you will be shaking your heads and thinking, “I am not an optimist”, but look at the estimates we make for how much time it will take to develop a particular piece of software and I think it is clear that we are all optimists. We are all optimistic about how easy a problem is going to be to solve and I think this is really valuable. If we weren’t optimists we might struggle to come into work in the morning and believe we are going to be able to fix all these problems.

I think we are also optimists about the size of our brains. We are all smart people working on complex problems and we imagine we can hold a lot more complexity in our brains than we really can and we overestimate our ability to handle complexity.

Secondly, we are all impatient. We get excited by finishing the problem, by showing the working software and so we want to get to the end as soon as possible. That comes from a good place but it does mean that we are tempted to make much more complex steps than really make sense and then we get slowed down, get caught in the weeds, and it takes much longer than it would otherwise.

Slide 010
We can learn to get better at this and I think your version control system can help.
Slide 011

I will take you through 5 habits that I think will really help

  1. Plan your commits
  2. Use single purpose branches
  3. Make atomic commits
  4. Write good commit messages
  5. Rewrite your history to tell a story (early and often)
Slide 012

Image courtesy of Alexander Baxevanis (CC BY)

If we take a look at the first of these, plan your commits.
Slide 013
This is simple, make a plan for the commits you are going to make to fix the bug or deliver the feature you are working on when you start.
Slide 014

Some of you will be sitting there thinking, “When I start working on a problem I don’t know enough to make a plan”. I would argue that if you don’t know enough to make a plan then maybe you aren’t ready to write production code yet.

There is all sorts of work you can do to make the plan, to understand the problem better. You can read the code to better understand how your current system works. You may even write code, do a ‘spike’, to better understand how you might solve the problem. The focus should be how can I learn enough to make a plan.

Slide 015

Some of you will be thinking, “When I write code I am always discovering new things as I work and my plan changes all the time so why bother making a plan?”. But if you understand the problem well, making a plan is relatively simple.

If you discover new things then having a plan to compare against is really useful. Have I just added one more step that I had forgotten about? Great. Or am I now veering way off course and maybe should be asking the questions, am I still on the right track or do I need to take a bigger step back?

Slide 016

Plan your commits ahead of time and re-plan when you need to.

If the plan is more than 2 or 3 steps long then write it down. Stop yourself needing to keep it in your working memory.

Slide 017

Image courtesy of Jon Bennet

Habit 2, use single purpose branches.
Slide 018
When you start working on a bug or a feature then create a new branch and name it to reflect it’s purpose. Many of you will already have set up your command line to show you the name of this branch you are on, if you make a pull request that name will be used automatically.
Slide 019

You want to keep focussed on this purpose and this is easier said than done. Quite often you will notice that you have moved away from the work you were originally doing.

Again this can often be for very good reasons. As you open a new file perhaps you notice a typo or some outdated comments which are nothing to do with what you are working on at the moment. As a good developer you want to tidy that up and that’s brilliant but it’s not pertaining to the work you are doing right now.

If you stop and notice this then you can decide what to do.

Maybe you need to fix it now, perhaps this is a bug that needs sorting out. If so, then create a new branch and fix it there and then return to your work. Alternatively just write it down as something you are going to go back to, once you have finished this piece of work then you can go back to fix it up.

Slide 020

Another thing that is really helpful to do is notice if the commit you have made has value independently of the feature or bug you are working on.

A good test of this is to imagine that you come into work tomorrow and the feature you are working on is cancelled would you still want this commit in your code base.

Quite often you will. Perhaps you have been refactoring a bit of the code to make it easier to work on, in which case that commit has value independent of the work you are doing.

Slide 021

If this is the case then you can ‘cherry-pick’ this commit onto master.

You want to share this code back with your team as soon as possible because it is already making the code base better independently of the work you are doing.

Some of you will be familiar with git cherry-pick but for those of you who are not I will talk you through an example

Slide 022

Here’s an imaginary history of a git project.

We have commit A, and then commit B where master is, and then you have created your own development branch with commits C and D and I have coloured commit D red to show where HEAD is at the moment. That’s the branch you are currently on.

Slide 023
So checkout master.
Slide 024
There you go
Slide 025
Then you can cherry pick any commit you like from anywhere in your history onto the branch you are on. Typically you would refer to this by a SHA but if the commit you want is at the HEAD of a branch then you can use the branch name so that’s what I have done here - git cherry-pick your-dev-branch and that will cherry pick D and put it on master.
Slide 026
I’ve labelled it D` because it is not actually the same commit. It doesn’t have the same parent but it does have all the same code changes in. It is ready to share with your team and now you can go back to your work.
Slide 027
Checkout your branch again.
Slide 028
Slide 029
Before you keep going rebase your branch on top of master.
Slide 030
Git is clever enough to spot that commit D has already been applied to master and so when you rebase on top of master it disappears from your branch and you have a simple branch which is just dedicated to the work you are doing for the new feature.
Slide 031
Keep focussed by making each development branch single purpose
Slide 032

Image courtesy of lupusphotos (CC BY)

Habit 3: Make atomic commits
Slide 033
Decide the one change you are going to make and commit it.
Slide 034

When I talk about this people often ask me, “How big a change should I make?”

In general, in our communities, people make their commits too big, they put too many things in them. If you are in any doubt at all make them smaller.

There’s another reason for making them smaller. It’s quite easy to merge commits back together if you have made lots of little commits but it’s very hard to split commits again. Starting small means you can change your mind later but starting big means you are stuck.

Slide 035
One way to think about the size of your commit is to think about what’s the minimum valuable change that you can make.
Slide 036
Another way of thinking about it is to consider if, when writing a commit message, you are tempted to write ‘and’ then you have probably made two different changes. I did this and I did that, maybe that’s one commit to do this and then one commit to do that.
Slide 037

Again you are going to have to start noticing when you start doing something else.

This is really easy to do. You get something working and then, great, you want to get onto the next part of your plan and you don’t commit anything you just start this new piece of work. All of a sudden you’ve got 3, 4, 5, 6 changes all sitting there unstaged in your repository.

Slide 038

Another useful tool that git offers to help with this is git add --patch.

Normally when you use git add you give it a filename or a directory and it just adds every change in the file or directory. This makes it very easy to inadvertently add multiple edit from different sorts of changes you want to make to your code base.

Slide 039
If you use git add --patch it will walk you through each chunk of changes you have made in turn and ask you whether you want to stage it or not. You can say “yes” or “no”. There are other commands to explore as well, you can split up, or edit etc. but “yes” and “no” will get you a long way.
Slide 040
Make each step you take simple by making atomic commits
Slide 041

Image courtesy of Ginny (CC BY-SA)

Habit 4: Write good commit messages
Slide 042

We all know what bad commit messages look like.

I have written variations of all of these in the past. I didn’t take these from a real project, I used a bad commit message generator available on the internet but you’ve all seen these.

What’s wrong with these messages? They don’t tell you what’s going on. The only way you can tell what’s happened with this history is going into each one and looking at the differences to the code.

We can do better.

Slide 043
What does good look like?
Slide 044

Here’s a template to help you think about this.

Not every bit is required for every commit but it is a useful thing to think through.

Short one line title to show what you have achieved in the commit. This is really important because you will often see lists of commits and so it is this title you will see most of the time.

Slide 045
Sometimes that short description is not enough and so you can provide a longer description. You have lots of space in a commit message.
Slide 046

Another thing that is really useful to add and get out of your head is an explanation of why you made the change.

This information you will forget very quickly. Even the next day when you look back you may have forgotten but if you write it in the commit message then you can always look back at it.

Slide 047

Lastly if it is a more unusual change it can be valuable to provide a discussion of the context or of the alternatives considered.

When you make the commit you will know more about the why and how of all the decisions you made than you ever will ever again and so it’s useful to get this out of your head so you don’t have to remember it.

Slide 048
Putting it all together
Slide 049

What does this look like in real life?

Here’s an example of a commit message that I didn’t write but I was responsible for the project.

You can see at the top a nice title to explain what has been achieved. Then a link to the project management tool we were using at the time. Then there is a more detailed description of what went on and why we have approached it in the way that we have and a link out to a blog post if you are interested in finding out more.

All of this information no longer needs to be in the head of the engineer who has written it and they can forget about it.

Slide 050
Clear space in your head, for focussing on the next problem, by writing good commit messages.
Slide 051

Image courtesy of Nic McPhee (CC BY-SA)

Fifth and final habit. Rewrite your history to tell a simple story and do this early and often.

People who leave this until the end just end up with a mess which is loads of work to rework and is often not worthwhile doing. If you do it early and often it is easy.

Slide 052
Git gives you a great tool for this - git rebase --interactive
Slide 053

…which allows you to remove, reorder, edit, merge and split commits.

Effectively it makes your development branch infinitely malleable.

Slide 054

To give you a simple of example of how this works

Imagine my plan was to ‘Add foo’ and then ‘Add bar’. But then I notice that I made an error when I first added foo, so I fix it and make one more commit, ‘Fix typo in foo’, giving me this git history.

That last commit is just noise, it’s not really interesting that I made a mistake first time round, so I can use git rebase --interactive to tell a simpler story.

Slide 055
If I run git rebase --interactive master, then git will open up that list of commits in your editor of choice.
Slide 056

You can see the three commits I made there ‘Add foo, ‘Add bar’ and ‘Fix typo in foo’.

By default git just picks each commit so if I save this I will just end up with the same list of commits. But you can edit this list. In the comments you can see a good guide to what you can do.

In this example what we will do is…

Slide 057
…swap the order of the commits and move the commit ‘Fix typo in foo’ immediately after ‘Add foo’ and…
Slide 058

…the second thing I will do is change ‘pick’ to ‘fixup’ for ‘Fix typo in foo’.

‘fixup’ squashes these changes into the previous commit and it throws away the second commit message leaving you with just the previous commit’s message.

Slide 059

When you save this it will make these changes and leave you with a simpler history, without the noise of the mistakes you made.

This is a simple example but if you have been working on something for a few days there may been quite a lot of that cruft unless you have been cleaning up.

Slide 060

Make your progress clear, so that you can see what you’ve done. That should be a list of nice short commit titles that match with the plan that you’ve got and tell a simple story about what you’ve done.

That will help you understand the work that you have done.

Slide 061

To recap:

  1. Plan your commits
  2. Use single purpose branches
  3. Make atomic commits
  4. Write good commit messages
  5. Rewrite your history to tell a story (early and often)
Slide 062

The three git commands I recommended were

  • git cherry-pick for pulling a commit from another branch onto the one you are on
  • git add --patch for stepping through each change you made and deciding whether to add it to your commit
  • git rebase --interactive to rewrite your history to tell a story of what you would have done if you hadn’t made mistakes
Slide 063

Following these 5 habits makes it much easier to work in small steps.

It means you can keep much less in your brain and can focus your brain on solving the problems you face rather than remembering all this cruft.

Slide 064
As an added bonus…
Slide 065

…it benefits to your team by providing great documentation for all your code.

If you’ve written good commit messages while you have been making changes then git blame will tell a great story about where a line of code came from. I have a whole separate talk on this if you are interested.

But I think the effect on your personal development is more important. Also this means you can benefit from these practices without persuading your team to adopt them too.

Slide 066
This is what allows Mislav Maronić to say that, “Every line of code is always documented”.
Slide 067
Thank you.

📊 Slides

Download the slides

Other versions of this talk

Further reading and watching


Thanks to @joelchippindale for presenting a great five point approach for helping to free up brain space using commits wisely. @python_london


✏️ Edited in Nov 2019 to add the transcript

This is part of a series of talks and articles about the work and practices of my teams and I at Unmade.