Your commit history is the story you tell your team. Right now it probably reads like a messy first draft: wip, fix, oops, "actually works now". Git gives you a safe way to rewrite that story into something readable — but only for commits you have not pushed yet.
1. Start the rebase
git rebase --interactive (short: git rebase -i) replays a range of commits and lets you decide what happens to each one: keep it, squash it, reword it, or drop it.
Point the command at the commit before the ones you want to edit:
# edit the last N commits
git rebase -i HEAD~3
# edit everything on your branch since it left main
git rebase -i main
HEAD~3 means "three commits back from HEAD" — it edits the three commits after that point, not the commit itself.
2. Read the todo list
Your editor opens a file listing the commits, oldest first:
pick a1b2c3d add login form
pick b2c3d4e fix typo
pick c3d4e5f more css tweaks
Each line has a command word, a commit hash, and a short message. Git executes them top to bottom when you save and quit.
3. Know the commands
The first word on each line decides what happens:
pickorp— keep the commit as is (the default)rewordorr— keep the change, pause to edit the messageeditore— stop so you cangit commit --amend, then continuesquashors— fold into the commit above, then combine messagesfixuporf— fold in but discard its messagedropord— remove the commit
4. Squash three commits into one
Say your last three commits are scattered typo fixes. Run:
git rebase -i HEAD~3
Keep the first line as pick and change the other two to squash:
pick a1b2c3d add login form
squash b2c3d4e fix typo
squash c3d4e5f more css tweaks
Save and close. Git asks for one combined message (it merges the three originals for you), and when you save again the three commits collapse into one. git log --oneline now shows a single clean commit — the code is identical, only the history is tidier.
5. Reword and drop
To fix just a commit message, mark its line reword: Git stops, lets you retype the message, and continues without touching the code. To remove a commit entirely, change its line to drop (or delete the line). It is usually safer to drop than to hand-edit a previous commit's contents by force.
6. The critical warning
Never rebase commits that already live on a shared branch. Rebase creates new commits with new hashes, so the rewrite diverges from what your teammates pulled. Putting it back on the remote requires a force push, and git push --force-with-lease at best — which can silently overwrite their work. Keep interactive rebase for local, unpushed commits only.
7. Recover from mistakes
If a rebase goes wrong mid-way, bail out:
git rebase --abort
That returns your branch to exactly where it was when the rebase started. If you only notice a problem afterwards, git reflog shows every place HEAD has been; git reset --hard <sha> jumps back to the one you want. Nothing is ever lost while the commit still exists.
Interactive rebase does not change what your code does — it changes how your work reads. Squash the noise, write a straight story, then push.