Squashing combines multiple commits into one. Manual way: rebase -i, change pick to squash (keeps message) or fixup (discards).
Autosquash is the magic. When you spot a bug in commit abc123:
git commit --fixup=abc123 -am "actual fix"
Later, before pushing:
git rebase -i --autosquash HEAD~10
Git automatically reorders your fixup! commits next to their targets and marks them as fixup. One keystroke (save the editor) and you're done.
Set it as default behavior:
git config --global rebase.autosquash true
Pair with commit --fixup while reviewing your own PR — your final history reads as if you got it right the first time.