Summary: Squashing is a good tool to have, but not everything should be squashed away. Intermediate commit history can have value. Please don't squash rework on a PR during the review phase. If you do, the reviewers may have to start over from scratch.
In this article I want to talk about when it is appropriate to be squashing (flattening) a series of commits in to one commit. I assume that we are using a branch for each issue (such as a bug or a feature), and we merge that branch to the main branch when it is considered finished, tested and properly reviewed.
Why do we squash during development?
In my experience it is good practice to commit often. It allows us to easily revisit or roll back any specific step that we take towards the final version of our code. This makes the process of finding the desired solution easier. When it comes time to share our work, we might want to squash our commits.
After we decide that we have found a sufficient solution for a specific problem, the road we took may not seem interesting anymore. At that point we are only interested in having solved the issue at hand. We might then squash a series of commits that we made while working towards this solution, and move on to the next problem.
There is another reason one might squash their commits. When we are writing code we make that code permanent by committing the code locally and eventually pushing it out to a central server, after which our code will be available to everyone. Sometimes we feel kind of bad about our earlier commits and don't want to make them permanently visible to others. Perhaps they were failed attempts and would show to others how little we understood when we started to work on this issue. This is also a valid reason to squash, and I don't want to minimize these kinds of feelings.
Whatever the reason, we decide to remove the earlier commits from existence such that only the final result remains in one neat commit.
Squashing is a good tool to have
Having a series of commits squashed in to one can be very handy when that commit eventually ends up on the main branch; with each issue contained to one commit it is a lot easier to research changes than when changes related to single issues are spread out over ten or a hundred commits. For that reason, I always squash before I merge an approved pull request.
Another reason is that it makes cherry-picking less error-prone and less time-consuming.
Squashing is great. However, there are also situations where I think we should not squash commits.
Not everything should be squashed away
Some pull requests contain a large amount of changes done in several steps that are clearly separate topics in the minds of the developers. In these cases it can be beneficial to do these steps one by one and squash the commits for one step in to one commit before proceeding to the next step. This will make the end result easier to review because it is still separated in understandable steps. It also makes it easier to get review comments on intermediate work; this can be important if the requested changes have impact on the next steps.
A situation where one should not squash at all is when one is committing rework in response to changes requested by reviewers. The reviewers are not as focused on your work as you are. They did the review and went on to another activity. By the time they get back to your pull request to see what has changed since the last time they looked at it, the reviewers will not remember the exact state of your branch before you did rework and squashed the branch again. The reviewers probably can't be certain if your rework has even improved the branch. Your reviewers will have to redo the entire review as a result of you squashing the rework on top of your original work. By the time they are half-way through re-reviewing your work they might be quite tired and have difficulty keeping focused on giving the pull-request a high-quality review.
We can save our colleagues as well as ourselves some time by taking a moment to consider before we squash. Our reviewers will be grateful!