git fixup
02 Feb 2018When using git sometimes you want to make a change and include it with the previous commit. The easiest way to do this is:
$ git add <files>
$ git commit --amend --no-edit
Sometimes you want to include your change in a commit before the previous one. To do this takes a few steps.
fixup! and --autosquash
The general way to edit history in git is with git rebase -i
. This does an interactive rebase, which allows you to re-order, remove, edit, and squash commits.
When you do git rebase --help
, you find this documentation about --autosquash
:
--autosquash
When the commit log message begins with "squash! ..." (or "fixup! ..."), and there is already a commit in the todo list that matches the same ..., automatically modify the todo list of rebase -i so that the commit marked for squashing comes right after the commit to be modified, and change the action of the moved commit from pick to squash (or fixup). A commit matches the ... if the commit subject matches, or if the ... refers to the commit’s hash. As a fall-back, partial matches of the commit subject work, too. The recommended way to create fixup/squash commits is by using the --fixup/--squash options of git-commit(1).
This option is only valid when the --interactive option is used.
So if we have a commit with the message fixup! <commit-hash>
where <commit-hash>
is the hash of the commit you want your changes to be included in, we can do git rebase -i --autosquash
to get the rebase command to automatically re-order the commits and mark them for being squashed.
$ git add <files>
$ git commit -m "fixup! <commit-hash>"
$ git rebase -i --autosquash
Then the interactive rebase editor opens and you have to save and exit. This isn’t as nice of a workflow as git commit --amend --no-edit
because you need to make a new commit, and open a text editor during the interactive rebase.
git fixup <commit-hash>
We can add a new git command git fixup
by adding an executable called git-fixup
on our path.
Here is the contents of my git-fixup
script:
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "usage: git fixup <commit>"
else
COMMIT=$(git rev-parse "$1")
numstaged=$(git diff --cached --numstat | wc -l)
if [ $numstaged -gt 0 ]
then
git commit -m "fixup! $COMMIT"
fi
GIT_SEQUENCE_EDITOR=true git rebase -i --autosquash --autostash $COMMIT^
fi
To use this script, save it with the name git-fixup
somewhere in you PATH
. Make sure you make it executable. Then you simply find the commit hash of the commit you want to modify and type:
$ git add <files>
$ git fixup <commit-hash>
This is very similar to the git commit --amend --no-edit
workflow.
Remember, git rebase --autosquash
only works for interactive rebases. In order to skip the interactive portion of the rebase we set the environment variable GIT_SEQUENCE_EDITOR=true
during the git rebase -i
command, which will automatically accept the suggested rebase actions.