---
title: "Git Fixup Explained: How to Clean Up Your Commit History Like a Pro"
description: "How to use git fixup to clean up your commit history"
author: "Bartosz Mikulski"
author_bio: "Principal AI Engineer & MLOps Architect. I bridge the gap between \"it works in a notebook\" and \"it works for 200 million users.\""
author_url: https://mikulskibartosz.name
author_linkedin: https://www.linkedin.com/in/mikulskibartosz/
author_github: https://github.com/mikulskibartosz
canonical_url: https://mikulskibartosz.name/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
```

![git log --oneline](/images/2019-01-09-git-fixup-explained/git_log_oneline.png)

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
```

![git rebase -i HEAD~3](/images/2019-01-09-git-fixup-explained/git_rebase_head_3.png)

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`.

![git rebase -i --autosquash 7dbe2a9](/images/2019-01-09-git-fixup-explained/git_fixup.png)

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
```

![git log --oneline](/images/2019-01-09-git-fixup-explained/git_log_oneline_2.png)

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.

![git commit --fixup 1e30877](/images/2019-01-09-git-fixup-explained/git_commit_fixup.png)

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.

![git rebase -i --autosquash 7dbe2a9](/images/2019-01-09-git-fixup-explained/git_rebase_autosquash.png)

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:

![git add -p file](/images/2019-01-09-git-fixup-explained/chunks.png)

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

![git add -p file](/images/2019-01-09-git-fixup-explained/two_chunks.png)

I won’t explain how to add chunks or split them because there is an excellent explanation <a href="https://stackoverflow.com/a/1085191/1078108">on StackOverflow</a>.

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:

![git rebase -i --autosquash 7dbe2a9 --autostash](/images/2019-01-09-git-fixup-explained/cannot_rebase.png)

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
```