Your pull request has commits called wip, fix typo and asdf. Before anyone reviews it, let's turn that mess into clean, meaningful commits with git rebase -i.
Every command and hash below came from a real repository I ran this in.
Video version:
Before: a messy branch
$ git log --oneline 2c27ca8 Add login tests fc5d50d asdf 4ffd51f fix typo 3e5db2d wip 3d66ed5 Add login form 6b96e5f Initial commit There's one real commit for the login form, three junk commits that are really part of it, and then the tests. We want two clean commits: "Add login form" and "Add login tests".
Step 1: start the interactive rebase
$ git rebase -i HEAD~5 Git opens your editor with one line per commit, oldest at the top:
pick 3d66ed5 Add login form pick 3e5db2d wip pick 4ffd51f fix typo pick fc5d50d asdf pick 2c27ca8 Add login tests pick means "keep this commit as it is".
Step 2: change the commands, save and close
pick 3d66ed5 Add login form squash 3e5db2d wip squash 4ffd51f fix typo squash fc5d50d asdf pick 2c27ca8 Add login tests | Command | What it does |
|---|---|
squash (s) | merge into the commit above, and edit the combined message |
fixup (f) | merge into the commit above, and discard this message |
reword (r) | keep the commit, change its message |
drop (d) | delete the commit |
| (move a line) | reorder commits |
Save and close the editor. Git replays the commits and asks you for the final message of the squashed commit.
After: clean history
Successfully rebased and updated refs/heads/main. $ git log --oneline 65399a2 Add login tests ae3841d Add login form 6b96e5f Initial commit There are two clean commits now. Notice that the hashes changed: rebase creates brand-new commits, which is why the safety rules below matter.
Pro tip: --fixup + --autosquash
Found a bug in an older commit? Don't make a "fix typo" commit and clean it up later by hand. Tell Git which commit the fix belongs to:
$ git commit -a --fixup=ae3841d $ git log --oneline 13275fc fixup! Add login form 65399a2 Add login tests ae3841d Add login form Later, rebase with --autosquash. Git moves the fix to the right place and marks it as fixup automatically:
$ git rebase -i --autosquash HEAD~3 pick ae3841d Add login form fixup 13275fc fixup! Add login form pick 65399a2 Add login tests Just save and close. You don't have to edit anything by hand. Set git config --global rebase.autoSquash true to make it the default.
Safety rules
- Only rebase commits that aren't on a shared branch. Never rewrite
mainafter others have pulled it. - Already pushed your own feature branch? Use
git push --force-with-lease, not--force. It refuses to overwrite commits someone else pushed in the meantime. - Conflict or panic mid-rebase?
git rebase --abortputs everything back. - Regret it after it's finished?
git reflogstill has your old commits.
Cheat sheet
-
git rebase -i HEAD~N: edit the last N commits -
squash/fixup: merge into the commit above -
reword: change a message ·drop: delete a commit -
git commit --fixup=<hash>+git rebase -i --autosquash -
--force-with-lease,--abort,reflog
Does your team squash commits, or keep them all? 👇
I post one tested coding tip every day on YouTube at Refactorly. The 30-second version of this one is here.

