Combining git commit --fixup and git rebase --autosquash for Cleaner Commits

Use git commit --fixup to mark correction commits and git rebase --autosquash to automatically squash them into the original commits, producing a clean, linear history without manual todo editing.

The tiimgreen/github-cheat-sheet repository documents this workflow in README.md (lines 929-936), with translations available in README.zh-cn.md, README.zh-tw.md, README.ja.md, and README.ko.md. Combining git commit --fixup and git rebase --autosquash allows you to amend previous commits without manually resolving complex rebase todo lists or risking accidental merges with unrelated changes. This technique ensures your git log remains readable while preserving the logical grouping of related code changes.

How git commit --fixup Works

According to the source documentation, git commit --fixup creates a temporary correction commit that targets a specific previous commit. When you execute:

git commit --fixup=abcde

Git generates a new commit whose message is automatically prefixed with fixup! followed by the subject line of the target commit abcde. This commit serves as a placeholder meant to be squashed into the original commit during a subsequent rebase operation. The --fixup flag also sets the GIT_REFLOG_ACTION environment variable to clearly mark the commit's purpose in the reflog.

How git rebase --autosquash Works

The --autosquash flag for git rebase automates the tedious aspects of interactive history rewriting. When enabled, Git scans the commit sequence for messages beginning with fixup! or squash!. It then automatically reorders these fixup commits to appear immediately after their target commits and changes the command from pick to fixup in the todo list. When the interactive rebase editor opens, the commits are already staged for automatic squashing—simply save and close to complete the merge.

Why Combine These Commands?

Using git commit --fixup with git rebase --autosquash provides three distinct advantages over manual rebasing:

  • Speed – You avoid remembering exact commit hashes or manually editing rebase todo lists to reorder and squash commits.
  • Safety – The autosquash mechanism guarantees fixup commits are applied only to their intended targets, preventing accidental merges with unrelated changes.
  • Clean history – The final result contains single, logically grouped commits that make code review and git log output significantly easier to read.

Step-by-Step Workflow

Identify the Target Commit

First, locate the commit you need to amend using the repository history:

git log --oneline --decorate

Note the commit hash (e.g., abcde) that requires correction.

Create the Fixup Commit

Make your required changes in the working tree, then create a fixup commit targeting the specific hash:

vim src/main.py
git commit --fixup=abcde

This creates a commit with the message fixup! [original subject line], clearly marking it for later squashing.

Execute the Autosquash Rebase

Initiate the rebase from the parent of your target commit with the autosquash flag:

git rebase abcde^ --autosquash -i

When the interactive editor opens, Git will have already reordered the fixup commit directly after the target and set the action to fixup. Save and close the editor—Git automatically squashes the fixup content into the original commit via a fast-forward merge.

Verify the Results

Confirm the fixup was successfully merged and the history is linear:

git log --oneline --decorate

The temporary fixup! commit should no longer appear as a separate entry; its changes are now part of the original commit.

Underlying Mechanics

During the rebase operation, --autosquash parses the todo list and inserts fixup lines immediately following their respective targets. When the rebase completes, Git performs a fast-forward merge of the fixup content into the original commit. This process preserves the original commit's metadata—including author name, email, and timestamp—while updating the tree content. The GIT_REFLOG_ACTION variable set during the initial git commit --fixup operation ensures these actions are clearly tracked in the repository's reflog.

Summary

  • git commit --fixup=<hash> creates a marker commit prefixed with fixup! that targets a specific previous commit.
  • git rebase --autosquash automatically detects these marker commits, reorders them after their targets, and prepares them for squashing without manual todo editing.
  • This combination ensures speed and safety while maintaining a clean, linear history.
  • The underlying mechanics use fast-forward merging and reflog actions to preserve commit metadata while updating code content.

Frequently Asked Questions

What is the difference between fixup! and squash! in Git?

Both prefixes trigger autosquash reordering, but they behave differently during the rebase. A commit marked with fixup! is automatically squashed into the target commit and its message is discarded. A commit marked with squash! is also combined with the target, but Git pauses to let you edit the final commit message, allowing you to combine or rewrite the descriptions.

Can I use --autosquash without interactive mode?

No, --autosquash requires the -i (interactive) flag to function. The autosquash mechanism works by pre-populating and modifying the interactive rebase todo list before the editor opens. Without interactive mode, Git has no opportunity to reorder the commits or set the fixup commands.

How do I fixup multiple commits at once?

You can create multiple fixup commits targeting different original commits, or even multiple fixups for the same target. Run git commit --fixup=<hash> repeatedly for each change. When you execute git rebase --autosquash -i, Git will reorder all fixup commits to appear immediately after their respective targets, stacking multiple fixups in sequence before the final squash operations.

Does using fixup and autosquash change the original commit's SHA?

Yes, the original commit receives a new SHA-1 hash because its tree content changes when the fixup is merged. However, Git preserves the original commit metadata including the author name, email, and original timestamp. The reflog maintains the history of these operations via the GIT_REFLOG_ACTION variable set during the fixup commit creation.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →