Making git history great again
My previous post covered how to write bitesize commits (spoiler: use git add -p
).
And there you go, a very clean git history! But what if you notice another spacing error after you’ve already commited?
Ugly. Let’s try that again.
Much better. The --amend
option adds your changes to the latest commit. The --no-edit
option means it’ll keep the original commit message. Congrats, you’ve rewritten history!
It’s not always so easy though. Let’s say that after running all tests, you realize your bugfix broke one obscure test you didn’t even know existed. You fix that test to pass, and then what?
Ugly. There’s one more step you need to do.
git rebase -i
What we want to do is rewind history, skip to before that spacing fix commit, and then amend our test fix changes into the original bugfix commit. git rebase -i
lets us do that.
The naïve way of doing this would be to stash our changes (rather than commit them), and then opt to edit the bug fix commit:
This will bring the interactive rebase editor:
Since we want to change the first commit, we replace that first pick
with edit
and save out of the editor. That will start the rebase, pausing after the first commit.
That works, but there’s a better way of doing it. Rather than dealing with the stash and interrupting the rebase, we can use another tool from the interactive rebase editor: fixup
. Fixup squashes a commit into the previous one, discarding its commit message. Back to our example:
Back to the interactive rebase editor:
This time, let’s move the last commit to be behind the first one, and replace pick
with fixup
:
Save out, and the rebase will autorun to completion[1]. This gives us the same result as the stash strategy, but it still feels like a little too much work.
We can shave off part of the work by using git rebase
’s --autosquash
flag. That flag looks for specially formatted commits in order to prepare the rebase for you. Back to our example:
And now the editor opens up with our commits in the desired order and with the desired actions:
You can instantly save out, and the rebase will run. This saves us work in the interactive rebase editor, but now we need to worry about properly typing out our throwaway commit’s message. Surely there’s a better way?
The final piece: git commit
’s --fixup
flag. Rather than manually adding a message, we can use this flag and pass a commit reference or SHA, and git
will autogenerate the correct commit message for us:
This will give us the same text in the interactive rebase editor as above. Once again, all you need to do is save out.
1. Unless you have a rebase conflict somewhere.