I've been doing a lot of micro-checkpoint commits which I later squash recently. Like, sometimes 10 small commits for a feature, all of them half-broken and messed-up, but as a major project-level checkpoint. Reviewing the diffs as I move along really helps me understand what's going on, and I then squash all these into a single clean commit before pushing.