When working in a team or on an open-source project in a git-centered process, the general advice is to keep commits and pull requests (PRs) clean, small and focused.
The benefits of this advice are numerous:
Each commit or PR is small, making it easier and quicker to review.
Focused commits or PRs makes it possible to accept good changes quickly while allowing time for discussion about more controversial changes. If all of the changes are bundled together, it becomes harder to separate things.
Small, focused commits are easier to understand when looking at past history.
Small, focused commits are easier to revert in isolation if a critical issue is discovered.
Including semi-related changes such as reformatting or fixing whitespace makes the diffs harder to decipher.
These are important benefits; so much so that they are adopted almost unquestionably by most open source projects and many teams.
Are there any downsides to this advice?
In my opinion there are at least two.
Clean Commits Inhibit Smaller Improvements
The biggest downside I see is that this workflow discourages the kinds of small improvements that we would otherwise make as we go along.
As we’re implementing a change, we might read some related code that doesn’t otherwise need to change. We might notice a name that could be clearer, making the code more understandable next time. We might identify some duplication that should be extracted. We might want to fix some formatting issues.
If we’re following a policy of clean commits, we can’t make these kinds of “drive-by” cleanups because they’ll pollute our commits.
Even something as simple as having our editor set to trim trailing whitespace or insert a trailing newline at the end of the file can violate a clean-commit policy.
If we’re being conscientious, clean commits won’t stop us. We’ll create a new branch, make the changes we identified, and submit them as a separate PR. However, we often don’t feel like we have the time or energy to do this. Be honest with yourself: How many times have you walked away from doing this extra work because it didn’t feel worth it for such a “small” change?
As I’ve discussed before, any obstacles we introduce into our refactoring process will make it less likely that we’ll do the refactoring. Clean commits is one such obstacle.
Clean Commits Take Time
The other big downside I see is the time it takes to clean up our commits and PRs before submitting them. Usually, this isn’t much. We need to look over our changes before committing anyway.
But if we want to reorder or reorganize the commits in a PR, we have to take time to do an interactive rebase to clean things up. If we do those all the time, we’re probably pretty quick. But often this can involve going to look up some documentation. And then there are all of the conflicts we need to resolve along the way.
If we’re being extremely careful, we’ll want to be sure that each of the reorganized commits still pass all of the tests. That can take quite a bit of time and care.
I’m not suggesting that we completely abandon a clean commits policy. The benefits are real and important.
I am suggesting that we should pay attention to the downsides and consider whether the policy is delivering the benefits we think it is at an acceptable cost.
Maybe we want to consider altering our policy a bit to allow for drive-by cleanups. Or maybe we decide to be OK with commits that aren’t as well-organized as they could be in order to save time.
The trade-off point might be different for an open-source repository than for an internal project. I suspect the latter might be more tolerant of a relaxed clean commit policy.
As with anything, don’t just adopt a policy blindly; think through the costs and benefits and make a decision based on the balance of trade-offs you see in your environment.