Until recently, I told my team to squash all of their commits on a given feature branch to just one commit. Every feature branch consisted of just this one commit and could be integrated into develop so that develop read just like a sequence of features. After further consideration, I changed that. Here are reasons for both approaches:
- Clean timeline: development of features clearly visible because every commit is a feature.
- Commits representing work in progress (WIP) broke builds on CI-server.
- WIP-commits prevented “jumping a month into the past” for debugging and exploratory purposes because they are potentially broken (compile errors, failing tests).
- If feature branches are merged, a merge commit is created that represents the development of a feature.
- Tools like Git Bisect are much more powerful when dealing with small commits
- In IDEs like IntelliJ IDEA, feature branches in the Git history can be collapsed to provide a better overview
- Small tasks are better visible. For example, small bugfixes tended to be fixed in bigger feature branches, just to be never found again. “Yeah, this got fixed somewhere, but I don’t know where”-syndrome.
- Every commit causes the CI-server to build. The more (pushed) commits, the more builds, the faster feedback if something went wrong.
To get the most out of the new strategy, each commit must
- compile and run green (all tests) AND
- have a good commit-message (see 7 rules of good commit messages )
Furthermore, really small commits may be merged with a fast-forward-merge / rebased onto develop.
Also, commits that represent a quick-WIP-save have to be edited in retrospect and provided with a good commit message. This is the last remaining situation, in which a squash is allowed
We don’t do squashes any more.
(Image: Dmitrij Drandarov)