What we do is to have a developement branch, with the real history. When ready for merge/review, we duplicate that branch, rebase -i (on the same origin) to clean it all up without making any changes -- changes aren't allowed, only history split then merge the clean branch in the dev one (no conflicts: no changes!) and THEN ask for reviews on that clean branch.
If there are further changes, park the 'clean' branch, continue working on dev branch as before, and make any changes needed (typically we use the 'autosquash' naming convention), and re-do the cleanup before re-submitting.
Once the review is complete, just merge again dev<->clean, and merge that in the trunk.
That way you have the whole history complete, and you also have a set of 'public' patches that have been reviewed and potentially can be upstreamed.
The author is correct that a rebase may require resolving conflicts; but then those conflicts need resolving anyway if you choose to merge instead. It is also possible to miss a "semantic conflict" that doesn't make git complain but produces a commit that doesn't build -- you can put in tooling that checks that each commit builds individually to avoid the "oops, bisect on master isn't much use" issues.