Avatar (Fabio Alessandro Locati|Fale)'s blog
Squash git commits

Squash git commits

September 14, 2026

I often review git pull/merge requests (PRs) both for work and open source projects. Many of those PRs have a number of commits with commit messages like “fix”, “actual fix”, “fix again”, or other similar forms. I understand why this happens, even more in repositories where it is far easier to trigger the continuous integration (CI) pipeline, rather than execute the tests manually. Having multiple commits in a PR is not problematic by itself, since it might make sense to slice the accomplished work further than 1 commit per PR, but it needs to be done in a logical way.

This problem can be easily fixed by squashing the commits. Squashing means taking a sequence of commits and combining them into a single commit, so the result is one commit on the target branch that contains all the changes, with one commit message, instead of the original chain. The history you keep while working on a branch is useful to you, but it is rarely useful to anyone reading the result.

I believe the PR creator should clean up the git history, at least up to the point of creating the PR. After the PR is created, reviewers may request changes; in that case, the submitter can add one additional commit for each comment they address.

Although there are multiple ways to tweak the git history, I think the only one that is worth learning and discussing is the interactive rebase, since it provides fine-grained control over each commit, allowing you to craft the history to a very satisfactory level.

The way to start an interactive rebase is by executing, in the feature branch:

git rebase -i main

This opens an editor with a list of all the commits on your branch since it diverged from main. Alternatively, if you want to manage a set of commits (for example, 5) independently of when it diverged from another branch, it is possible to use:

git rebase -i HEAD~5

In both cases, the opened editor will list all commits you can operate on, and for each commit you can choose what to do: pick it as-is, reword its message, squash it into the previous one, drop it, and a few other options.

pick 1a2b3c4 Add initial implementation
pick 5d6e7f8 Fix typo in variable name
pick 9a0b1c2 Handle edge case with empty input
pick 3d4e5f6 Update documentation

To fold the typo fix and the edge case fix into the initial implementation, you would change it to:

pick 1a2b3c4 Add initial implementation
squash 5d6e7f8 Fix typo in variable name
squash 9a0b1c2 Handle edge case with empty input
pick 3d4e5f6 Update documentation

You can also use s instead of squash, which is very convenient if you have many commits to manage.

After saving, git prompts you to write a new commit message for the squashed commits.

I tend to always use this approach since the additional effort is, in my opinion, very modest and I prefer to always be intentional in the refinement of the git history.

Conclusions

Squashing is one of those topics that sounds like a git technicality but is really about who the history is for. The history you produce while working is for you; the history that lands on the target branch is for everyone else, including a future you who will have forgotten the details.

By cleaning up your git history before you push commits to the PRs, you are making it simpler for the reviwer to review your change and, at the same time, you are ensuring that whoever will try to pinpoint a problem or a change of behavior will have more ability to quickly understand when was changed and why.