Interactive rebase is Git's primary tool for cleaning up commits before sharing them. Running git rebase -i HEAD~5 opens an editor listing the last five commits; you can reorder lines to change their order, change pick to reword to edit a message, edit to pause for amendments, or squash (and fixup) to combine a commit with the previous one. The common shorthand git rebase -i HEAD~3 followed by changing every line except the first to squash collapses three commits into one. For PR-friendly workflows, git commit --fixup <sha> tags follow-up commits and git rebase -i --autosquash main automatically organizes them into the right place.
Rebases can be interrupted safely. If you change your mind mid-way, git rebase --abort returns the branch to its original tip with conflicts and all. After resolving a conflict, git add the fixed files and run git rebase --continue to apply the next commit; if you decide a commit should be dropped entirely, git rebase --skip does so. For long-running rebases, git rebase --edit-todo lets you insert break lines that pause the rebase so you can run tests before continuing.
Rebasing is also the cleanest way to incorporate upstream changes without a merge commit. On a feature branch, git rebase main replays your commits on top of the latest main; combined with the global setting git config --global pull.rebase true, even git pull will rebase instead of producing the "ugly merge commit" pattern that the default merge-based pull creates. To make a single commit from messy history, git reset --soft main collapses all your work into staged changes, and a fresh git commit -m 'clean message' produces one tidy commit.