Second, if I do create a feature that should be multiple commits for clarity, I find it a lot easier to do all my work in a scratch feature branch, get everything working correctly, tests passing, etc., then do a `git merge --no-commit` onto my final feature branch for the PR. At that point I can break my work up into a few different commits, as necessary.
For me, rebasing is the means by which I keep my development branch neat and tidy. Each commit changes one thing. It's easy to see what's "prep work" and what's the ultimate change of functionality. Git bisect can find the commit that caused a bug. And so on.
I view squash merges largely used as a crutch to hide bad habits. I find the resulting history from lots of squash merges is not useful in figuring out why a change was made; by that time the specific change is part of a big ball of mud with a very vague high-level goal.
Possibly? But I also find it hard to believe that there's this many developers out there typing out perfect code on the first try with no mistakes or false starts.
> I find the resulting history from lots of squash merges is not useful in figuring out why a change was made; by that time the specific change is part of a big ball of mud with a very vague high-level goal.
That's the developer's fault though. If someone is lazy enough to squash-merge a big ball of mud onto the main branch, they would also be lazy enough to generate a commit history filled with barely working and unclear commits, or incompetent enough to completely hose themselves with a rebase.
At the end of the day, I'm generating the same set of small, atomic commits as you. The difference is that I don't spend any time worrying about what the commit history looks like while I'm coding. It's only at the last second before sharing a PR that I consider it. 95% of the time I've got a tight one-commit PR containing a little code, a few docs, a few tests. Sometimes I break my changes into separate PRs, very rarely I'll add multiple commits to a single PR, but those aren't my default workflows.
Version control in the private branch is a tool which helps me maintain state and go back and forward in time. It looks exactly like I thought about the code or work I needed to do at some point in time. It is not messy or tidy, it's just what it is. I don't have to please anyone's sensibilities when I'm in the private branch.
The merge into main is squashed and atomic, of course.
Cleaning up one's own mess is what git rebase -i is for.