Git protip: easily add missing changes to an old commit
By Maxime Bréhin • Published on 17 October 2022
• 2 min
How many times did you forget to add a file or change to a commit, only to discover your mistake later on (after a few commits)?
Since I’m a strong proponent that atomic commits are key to project quality and automation (see Conventional Commit and Semantic Release, for instance), I do my best to fix these commits using Git interactive rebasing. I strongly recommend you do the same. You don’t have to be afraid of Git rebase, you just have to learn how to use it 😉.
My goal here is to help you do this in a quick, smooth, painless way.
You may already be familiar with the git commit --fixup
option (or --squash
) that creates a commit with a special-format message about our intent to fix another commit. Using that, when you run a properly-configured interactive rebase, Git will automatically move that commit line as a fixup next to the one you’re fixing.
Step by step
Add the missing files to the stage: git add …
.
Ask Git to create the fixup commit: git commit --fixup=<commit-ref-to-be-fixed>
.
Then run an interactive rebase, starting one commit before the one you fixed: git rebase --autosquash -i -r <fixed-commit-ref>~1
.
Git opens your editor with the list of actions to run, but with the fixup already in the right spot. There’s nothing more to do except save and close the file, that’s it !
pick 3f0714b chore(dx): setup ESLint and Prettier
fixup 61eecda fixup! chore(dx): setup ESLint and Prettier
pick 9a7cf39 chore(dx): setup Husky, lint-staged, precommit-checks, commitlint
You might want to check your log to confirm everything’s fine. You may also want to check that all the intended files were recorded by the fixed commit git show --name-only <new-commit-ref>
.
As this is a recurring thing for me, I made a “magic” 🧙♂️ alias that calls both commands in sequence (to fix a single commit):
# Don't forget to stage the relevant fixes first
git config --global alias.autofixup '!git commit --fixup $1 && git rebase --autosquash --interactive --rebase-merges $1~1 && echo "autofixup finished"'
Et voilà !