Why would my messy history be useful for bisection? The places I committed, it may not have even fully compiled except for the very last commit. In that case, to separate the code in a useful way (such as 3 commits, one for each feature, each of which compiles on its own), you'd have to do a bit more work and create new commits, which again means either rendering the original commits pointless or disregarding them.
Surely your test-edit cycle involves at least some compiling. Maybe not every commit will compile, but most changes that compile will have a commit. At the very least a "real" commit has a much higher chance of compiling than an "artificial" one that you constructed retrospectively.
If you really do make most of your commits not compile then I can sort of sympathise with squash-merging, but if you merge then worst case it's a one-liner to bisect while only looking at "mainline" history (i.e. only the merges to master, the equivalent of what you'd get if you'd squash-merged), whereas if you squash-merge then there's no way to bisect back through the original history.
Compiling vs. not-compiling is only the tip of the iceberg; there’s a lot of other aspects of my development that don’t make sense until the very end. Arguably, the whole feature is basically useless until it’s finished; why would I keep working on it in any meaningful way after it is complete and running? If that happens, chances are that the ticket wasn’t atomic enough. There are exceptions of course, such as substantial rewrites for bug fixes, but those are by nature not the norm. As a result, my commit messages are only for me, which saves time in development. Commit messages “wip” and “working now” mean something to me, but definitely hold no value to whoever is doing a git blame in the future, which is another benefit of squashing.
If it compiles then I can use it in an automated bisect, which is the main thing VCS history is useful for IME. I'm a big believer in "refactor mercilessly" and "make the change easy, then make the easy change", so while obviously the final feature will not be working in the intermediate commits, the work will touch on other code areas and there's always the possibility that this will introduce a subtle bug that slips past the current test suite, and if that should happen then I want to be able to bisect down to the smallest possible diff before I start trying to understand it manually. I also find that a small commit with a useless message is actually a much more useful blame result than a big commit, even if the big commit contains a detailed explanation of the overall change.
> I also find that a small commit with a useless message is actually a much more useful blame result than a big commit, even if the big commit contains a detailed explanation of the overall change.
That's pretty interesting. I know with me, that is definitely not true, because 90% of all commits would just be the message `wip` which makes Git Blame incredibly hard to use.
What are you trying to get out of the blame? I do sometimes git tag --contains to find the overall feature that the blame-output commit was part of, but most of the time the most useful thing is just to see the diff for that commit or frankly even just the list of files it touches.
Much of the time it’s asking what the motivation behind a line of code is, such as why we take some crazy convoluted approach to what seems like it should be a simple task. Editor plugins such as Git Lens display the blame output so it is much more convenient if that information is in the commit rather than in an associated tag.
Why would my messy history be useful for bisection? The places I committed, it may not have even fully compiled except for the very last commit. In that case, to separate the code in a useful way (such as 3 commits, one for each feature, each of which compiles on its own), you'd have to do a bit more work and create new commits, which again means either rendering the original commits pointless or disregarding them.