I try hard to make each "commit" operation represent a single, cohesive change. Sometimes it's a whole bug fix or whole feature, and sometimes it's a single small refactoring on the way to something bigger. There's no simple way to decide what a unit is here, just by gut feel. I also ask (beg!) my teammates to do the same.
When this is done well, you get a number of benefits:
- You can write a high quality, detailed description for the change.
- Reading the first line of the description of each change gives you a sense of the flow of the code.
- The diffs of a change are easy to read & understand.
- If a change introduces a bug / build break / other problem, it's easy to isolate, understand, and back out if necessary.
- If I'm half-way through a change and decide to abort, I don't lose much.
- If I'm not sure how to proceed next, I can spend a few minutes on each of several approaches, and then pick the one I like, discarding the others.
- My coworkers pick up most of my changes sooner, dramatically simplifying the merge problem.
- When I'm feeling stuck about a big problem, I can take a few small steps that I'm confident in, checking them in as I go, thereby making the big problem a little smaller.
Working like this can help reduce the need for small branches, since you take a small, confident step, validate it, and commit it, then repeat. I've talked about how to make the step small & confident, but for this to work, you also need to make validation phase go quickly. Having a strong battery of fast, fine-grained unit tests + high quality, fast application tests is key.
Teams that I have worked on before required code reviews before checking in; that adds latency, which interferes with my small-step work style. Making code reviews a high-urgency interrupt works; so does switching to pair programming.
Still, my brain seems to like heavy multitasking. To make that work, I still want multiple in-progress changes. I've used multiple branches, multiple local copies, multiple computers, and tools that make backups of pending changes. All of them can work. (And all of them are equivalent, implemented in different ways.) I think that multiple branches is my favorite, although you need a source control system that is good at spinning up new branches quickly & easily, without being a burden on the server. I've heard BitKeeper is good at this, but I haven't had a chance to check it out yet.