Git fixup explained

Quite often, we must modify a file that has already been committed to the local repository. In this case, we often end up with commit messages like: “Fixed typo.”, “Added missing parameter.”, “Removed redundant import.”

At some point, we realize that such commit clutter the code history, and it is better to avoid them. Fortunately, there are at least two options to get rid of them.

git rebase -i

The simplest solution is to create the “fixup” commit with any message we want and then squash it with another commit.

In the first example, I created four commits. I want to squash the last one with the second one:

git log — oneline

Now, I am going to run the interactive rebase of commits between the current HEAD and the three last commits:

git rebase -i HEAD~3

I must move the commits around. The “Fixed a typo in second change.” commit must be below the second commit. Additionally, I have to change the command from pick to fixup.

Don’t forget to save the file opened by git rebase!

Done, I have commit history without artificial commits.

git commit — fixup

When I think that I may forget to run git rebase later, I use git commit with the fixup parameter to automatically move the commit in the proper place and mark it as fixup of change.

In this example, I have three commits. Imagine that, I have modified the file again, and I want to commit my changes as a part of the “Second change.” commit:

git log --oneline

I need the identifier of the commit I want to modify. In this case 1e30877:

git commit --fixup 1e30877

Git created a commit marked as a fixup, but it is in the wrong place! I need to move things around again.

First, I must check which commit was not affected by my recent change. I need its identifier. In my example, it is: 7dbe2a9.

Now, I must run an interactive rebase with the autosquash parameter:

git rebase -i --autosquash 7dbe2a9

It is going to open the rebase text editor we saw in the first example, but this time all changes have been automatically applied.

All I have to do is saving the file.

Change only a part of a file

Sometimes we want to fix a commit, but we have made many changes in the file, and only some of them should be squashed with a past commit. In such situations, we can use the patch parameter of the git add command to add only a part of the file to the commit.

Imagine that I have made two changes in the file, but only one of them should be used as a fixup:

git add -p file

This command opens a view with all the changes I have made since the last commit. I can add a chunk of the file to the next commit (stage the change) or leave it unstaged.

In my example, the chunk suggested by git is too large. I want only the first modification. Fortunately, it is possible to split a chunk into smaller parts:

Now, I have to decide whether I want the chunk or not:

I won’t explain how to add chunks or split them because there is an excellent explanation on StackOverflow.

Now I can use git commit with the fixup parameter to mark my changes as a fixup and then run the rebase to modify the commits. There is one little issue. I have not added the second chunk to the commit, so when I run the git rebase I get information about unstaged changes:

I can stash them, do the rebase, and unstash them back, but there is a shortcut. I can run rebase with the autostash parameter:

git rebase -i --autosquash 7dbe2a9 --autostash

One more shortcut

We don’t want to type autosquash and autostash every time we do a rebase, so we are going to enable them in the git configuration permanently.

git config --global rebase.autosquash true
git config --global rebase.autostash true

Now, all I must type is the identifier of the last unaffected commit:

git rebase -i 7dbe2a9
Older post

[book review] So good they can’t ignore you

A polarizing book

Newer post

Bootstrapping vs. bagging

The difference explained