- refactoring: one commit
- fixing a bug: one commit
- fixing another unrelated bug: another commit
- new feature: another commit
In old version control systems it might have been difficult to do this, but with git it's a breeze given some practice: even if you're in a middle of something, you can always stop working, do a temporary commit or stash; then checkout main branch, create a new branch; do the thing you want to do (refactoring or bugfix) in isolation; commit; then go back to the other branch, and rebase.
There's also git add -p for making partial commits if you did a lot of changes and want to commit only some of them.
Separating the activities would really ruin my workflow.
If you're designing new code and you write something, tear it down and bring it back up, but it's never touched the main branch, it doesn't matter how much you do to it.
In my standard development flow, I commit often, but don't PR, and then at the end, I rebase my whole branch on top of main and shrink it down to one-to-few commits, usually one.
Since people are only looking at the commit set at the end of my work in the pull request, that's the only thing that needs to follow the 'refactor vs new code' separation.
The thing is, once you get a habit of committing often (also unfinished WIP work) in small portions, with minimal effort you can then reorder and squash commits and make the final PR really much easier to review _even for yourself_, and twice as much for everyone else
Version control makes things so easy I typically always commit the refactoring work to mainline first (code review and all) then fix the bug or repeat with another refactor.
It’s also typically faster, because the refactoring alone is a significantly smaller code review than the refactoring+<change>, and I can keep working on the <change> (i.e. bug fix/feature/more refactoring) while that CR gets looked at.