There's a middle ground between squashing and leaving a load of disorganised crap in the history. Rebase before merging. It gives you a chance to clean up the rubbish, but it doesn't force you to squash an entire feature's work into a single commit. You can preserve the logical changes without letting the crap into your history.
But as part of your point that commits should be the "minimum necessary change", it makes sense to send a logical series of patches that iteratively change a project to implement a new feature (e.g. adding new infrastructure), rather than one big patch to implement that feature.
Yes, but WHY it does that may not be obvious. "Oh, this code checks for a funny condition, but why would we care about that?". That's what commit messages are for.
As someone in favor of squashing, I can say that I don't want to see things like "oops, reverting last commit" popup in my git history, especially if I'm browsing history or bisecting a bug. That's noise - useless data. OTOH, commits should be the Minimum Necessary Change to accomplish a well-defined goal. The code itself should always be clear on what it is doing, otherwise it's badly written. If it's "deep magic", then comment it in the code as such.
That being said, I do think that reasoning for why a change was made, at every level, should be in the commit message. I'm also not a fan of merge, but prefer squash+rebase.
In all cases/workflows, it can be abused, and people writing bad code, bad comments or bad commit messages will do so until you can make them care to do it better. There's no silver bullet.