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 reads just like a sequence of features. After further consideration, I changed that. Here are reasons for both approaches:
- Clean timeline: Development of features is 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.