The other day I was working on a pull request when I discovered I had forgotten something trivially simple that should have gone in the commit before the one I just made. If I hadn’t have made that other commit, I could just --amend it. I could git reset HEAD^, amend my commit, then restage and redo my second commit, but that’s a lot of steps and could get ugly in a hurry if the target commit was more than one commit back.
What would be perfect would be just making an extra ‘oops’ commit and squashing it later. But squash and fixup meld into the previous commit. If only there were a way to change the order of commits so I could squash as desired.
As it turns out, there is!
Reorder Git Commits with an Interactive Rebase
Reordering git commits is about as intuitive as it gets. Simply:
- start an interactive rebase – in my case with git rebase --interactive HEAD~3
- change the order of the commits in your editor
- save and quit.
You can even squash or fixup at the same time.
It’s even right there in the comments, though a bit opaquely: “These lines can be re-ordered; they are executed from top to bottom.”
‘Executed’ refers to the commands in your rebase (e.g. pick). So the reason this works is the pick command actually adds the commit. Order matters. I guess I always thought pick meant “yes keep this one” rather than “add this one to the end of the queue.”
As always, the standard history-changing caveat applies. If you’ve already pushed changes to a shared branch, you’re going to have to live with your oops commit. If you’re working on a private topic branch or you haven’t pushed yet, rebase away ;)