Git Autosquash
Git Autosquash: Automated Commit Cleanup
Git’s autosquash feature transforms interactive rebase from a manual,
error-prone commit organization process into an automated workflow that
intelligently arranges fixup and squash commits. Rather than manually reordering
and editing commits during git rebase -i, autosquash enables you to mark
commits for automatic squashing during development, then have Git handle the
organization during rebase.
This workflow optimization proves essential for maintaining clean commit history while preserving development velocity. You can commit frequently during feature development—including small fixes to previous commits—then automatically consolidate related changes before merging, producing professional, reviewable commit histories without manual intervention.
Prerequisites
Understanding autosquash requires solid familiarity with:
- Interactive Rebase: Core rebase operations, the todo list, and rebase mechanics. Review Interactive Rebase if needed.
- Commit History Rewriting: Understanding of when and why to rewrite history, and the safety considerations involved.
- Commit Identification: How to reference previous commits using SHA hashes and relative references.
Critical Safety Note: Autosquash performs history rewriting. Never use it on commits that have been pushed to shared branches without coordination with your team.
Architectural Foundation: The Autosquash Mechanism
The Manual Rebase Problem
Consider a typical feature development scenario:
# Your commit history during development:
abc1234 Add user authentication feature
def5678 Fix typo in auth function # Oops, should be part of abc1234
ghi9012 Add tests for authentication
jkl3456 Fix missing error handling # Should be part of abc1234
mno7890 Update documentationTraditional Manual Approach:
git rebase -i HEAD~5
# Interactive todo list appears:
pick abc1234 Add user authentication feature
pick def5678 Fix typo in auth function
pick ghi9012 Add tests for authentication
pick jkl3456 Fix missing error handling
pick mno7890 Update documentation
# Must manually reorder and change commands:
pick abc1234 Add user authentication feature
fixup def5678 Fix typo in auth function
fixup jkl3456 Fix missing error handling
pick ghi9012 Add tests for authentication
pick mno7890 Update documentationThis manual process is tedious, error-prone, and disrupts development flow.
The Autosquash Solution
Workflow with Autosquash:
# During development, commit with special prefixes:
git commit -m "Add user authentication feature" # abc1234
git commit --fixup abc1234 # Automatically creates: "fixup! Add user authentication feature"
git commit -m "Add tests for authentication"
git commit --fixup abc1234 # Another fixup for abc1234
git commit -m "Update documentation"
# When ready to clean up:
git rebase -i --autosquash HEAD~5
# Git automatically generates todo list:
pick abc1234 Add user authentication feature
fixup def5678 fixup! Add user authentication feature
fixup jkl3456 fixup! Add user authentication feature
pick ghi9012 Add tests for authentication
pick mno7890 Update documentationGit recognizes the fixup! prefix and automatically positions these commits
immediately after their target, with the fixup command already applied.
Commit Types: Fixup vs Squash
Git autosquash supports two commit types:
Fixup Commits (--fixup):
- Merge changes into target commit
- Discard the fixup commit’s message
- Use for small corrections, typos, forgotten changes
Squash Commits (--squash):
- Merge changes into target commit
- Preserve the squash commit’s message for editing
- Use for substantial additions requiring message updates
Practical Implementation: Basic Autosquash Workflow
Creating Fixup Commits
The most common autosquash operation: marking commits that should be absorbed into previous commits.
# Start feature work
git commit -m "Implement user login validation" # abc1234
# Continue development...
git commit -m "Add password strength checker" # def5678
# Realize you need to fix something in the login validation
# Make the fix, then:
git add login.py
git commit --fixup abc1234
# Git automatically creates commit with message:
# "fixup! Implement user login validation"
# Continue work...
git commit -m "Add session management"
# Another fix for the original login commit:
git add login.py
git commit --fixup abc1234Identifying Target Commits:
# Fixup the previous commit (HEAD~1)
git commit --fixup HEAD~1
# Fixup using commit SHA
git commit --fixup abc1234
# Fixup using relative reference
git commit --fixup HEAD~3
# Fixup using search string (Git 2.35+)
git commit --fixup :/authentication
# Finds most recent commit with "authentication" in messageCreating Squash Commits
When you want to add substantial changes to a previous commit but preserve documentation in the commit message:
# Original commit
git commit -m "Add email notification system" # abc1234
# Later, add significant functionality
git add email_templates.py
git commit --squash abc1234
# Git creates: "squash! Add email notification system"
# Opens editor for you to add description of new changes
# During rebase, you'll be prompted to edit the combined messageExecuting Autosquash Rebase
Once you’ve marked commits with --fixup or --squash, trigger the automated
organization:
# Standard autosquash rebase
git rebase -i --autosquash HEAD~10
# Shorter with config (see Configuration section)
git rebase -i HEAD~10 # If rebase.autosquash is enabled
# Autosquash with specific base
git rebase -i --autosquash main
# Autosquash onto upstream branch
git rebase -i --autosquash origin/mainWhat Happens:
- Git analyzes all commits in the rebase range
- Identifies commits with
fixup!orsquash!prefixes - Matches each to its target commit by message matching
- Generates rebase todo list with commits automatically reordered
- Applies appropriate rebase action (fixup/squash) to each marked commit
Advanced Techniques: Sophisticated Autosquash Usage
Chained Fixups
Create fixup commits for other fixup commits, building chains of corrections:
# Original feature commit
git commit -m "Add API endpoint" # abc1234
# First fix
git commit --fixup abc1234 # def5678: "fixup! Add API endpoint"
# Later, fix the fix (fixup of a fixup)
git commit --fixup def5678 # ghi9012: "fixup! fixup! Add API endpoint"
# During autosquash rebase:
pick abc1234 Add API endpoint
fixup def5678 fixup! Add API endpoint
fixup ghi9012 fixup! fixup! Add API endpoint
# All three get consolidated into abc1234Selective Autosquash
Use autosquash for specific commits while preserving others:
# Commit history:
# A - B - C - D - E
# Want to fixup only C, leaving others for manual handling
# Create fixup for C
git commit --fixup <commit-C-sha>
# During rebase, autosquash handles C fixup automatically
# Other commits available for manual reordering/editing
git rebase -i --autosquash HEAD~5Interactive Fixup Creation
Git provides a helper for creating fixup commits interactively:
# Show recent commits and create fixup interactively
git commit --fixup=reword:HEAD~3
# Opens editor to reword the target commit message
# Create fixup with message editing (Git 2.32+)
git commit --fixup=reword:<commit-sha>
# Amend the target commit message during fixup
git commit --fixup=amend:<commit-sha>
# Combines changes AND lets you edit target's commit messageGit 2.32+ Extended Fixup Types:
--fixup=<commit>- Standard fixup (discard message)--fixup=amend:<commit>- Fixup with message amendment--fixup=reword:<commit>- Reword target commit message only--squash=<commit>- Standard squash (preserve message)
Configuration and Defaults
Global Autosquash Enablement
Enable autosquash by default to eliminate the need for the --autosquash flag:
# Enable autosquash globally
git config --global rebase.autosquash true
# Now these are equivalent:
git rebase -i HEAD~10
git rebase -i --autosquash HEAD~10
# Disable for specific rebase if needed:
git rebase -i --no-autosquash HEAD~10Recommendation: Most developers benefit from enabling this globally. The automated organization prevents errors and saves time.
Autosquash with Auto-Stash
Combine autosquash with auto-stash for seamless workflow:
# Enable both features
git config --global rebase.autosquash true
git config --global rebase.autostash true
# Now you can rebase with uncommitted changes:
# Git automatically stashes, rebases with autosquash, then pops stash
git rebase -i HEAD~10Fixup Command Aliases
Create convenient aliases for frequent operations:
# Add to ~/.gitconfig:
[alias]
fixup = commit --fixup
squash = commit --squash
ri = rebase -i --autosquash
# Usage:
git fixup HEAD~2
git squash abc1234
git ri HEAD~10Enhanced Fixup Alias (interactive target selection):
# Add to ~/.gitconfig:
[alias]
fixup = "!f() { \
TARGET=$(git log --oneline -n 20 | fzf | awk '{print $1}'); \
git commit --fixup=$TARGET; \
}; f"
# Requires fzf (fuzzy finder)
# Usage: git fixup
# Presents last 20 commits interactively for selectionWorkflow Integration Patterns
Feature Development Workflow
Scenario: Developing a feature branch with frequent small fixes.
Approach:
# Start feature
git checkout -b feature/user-profiles
git commit -m "Add user profile model" # Commit A
# Add more functionality
git commit -m "Add profile view template" # Commit B
git commit -m "Add profile edit endpoint" # Commit C
# Discovered issues in earlier commits during testing
git add models/user_profile.py
git commit --fixup A # Fix for profile model
git add views/profile.py
git commit --fixup B # Fix for view template
# More feature work
git commit -m "Add profile image upload" # Commit D
# Another fix for the model
git add models/user_profile.py
git commit --fixup A
# Ready to merge - clean up history
git rebase -i --autosquash main
# Result: Clean history with fixes incorporated:
# - Add user profile model (with both fixes)
# - Add profile view template (with fix)
# - Add profile edit endpoint
# - Add profile image uploadCode Review Preparation
Scenario: Address review feedback without polluting history.
# Initial feature commits pushed for review
git push origin feature/api-refactor
# Reviewer comments on specific commits
# "Commit abc1234 has a typo in function name"
# "Commit def5678 missing error handling"
# Address feedback with fixup commits
git commit --fixup abc1234 -m "fixup! Fix function name typo"
git commit --fixup def5678 -m "fixup! Add error handling"
# Push fixup commits for reviewer to see incremental changes
git push origin feature/api-refactor
# Before final merge, consolidate with autosquash
git rebase -i --autosquash main
git push origin feature/api-refactor --force-with-lease
# Final history shows polished, logical commitsParallel Feature Development
Scenario: Working on multiple related commits simultaneously.
# Create several logical commits for a feature
git commit -m "Add authentication service" # A
git commit -m "Add authorization middleware" # B
git commit -m "Add user session management" # C
# While testing, find issues in all three areas
# Fix them incrementally as you discover them
git commit --fixup A
git commit --fixup C
git commit --fixup B
git commit --fixup A # Another fix for A
# Autosquash automatically organizes:
git rebase -i --autosquash HEAD~7
# Result: All fixes properly incorporated into their target commitsPerformance and Safety Considerations
Performance Characteristics
Time Complexity: O(n log n) where n is the number of commits in rebase range.
- Commit analysis: O(n) - Git scans all commits for fixup/squash prefixes
- Matching: O(n log n) - Message matching and todo list sorting
- Rebase execution: O(n) - Standard rebase complexity
Optimization Strategy: Limit rebase range to minimize commits analyzed:
# Suboptimal: Rebase entire branch history
git rebase -i --autosquash origin/main # May scan hundreds of commits
# Optimized: Rebase only recent development
git rebase -i --autosquash HEAD~20 # Scan only last 20 commitsSafety Mechanisms
Commit Matching Accuracy:
Autosquash matches commits by message substring. Potential issues:
# Ambiguous scenario:
git commit -m "Add user authentication" # A
git commit -m "Add user authorization" # B
git commit --fixup :/authentication # Intended for A
# Problem: "authentication" substring might partially match both
# Git uses most recent match (B) if ambiguous
# Solution: Use explicit commit SHA
git commit --fixup A # UnambiguousConflict Prevention:
# Verify todo list before executing
git rebase -i --autosquash HEAD~10
# Review the generated todo list carefully
# Exit editor without saving if organization looks wrong
# Use --edit-todo to modify mid-rebase
git rebase --edit-todoCommon Pitfalls and Solutions
Pitfall 1: Fixup of Pushed Commits
# Dangerous: Fixup commits that exist on remote
git commit --fixup abc1234 # abc1234 already pushed
git rebase -i --autosquash
git push --force # Rewrites public history!
# Solution: Only fixup unpushed commits
# Or coordinate with team before force-pushingPitfall 2: Message Matching Failures
# Problem: Commit message changed after creating fixup
git commit -m "Add feature X" # Original: abc1234
git commit --fixup abc1234 # Creates "fixup! Add feature X"
git commit --amend -m "Implement feature X" # Changes abc1234's message
git rebase -i --autosquash
# Fixup no longer matches - won't be automatic
# Solution: Use SHA-based fixup, not message-based
git commit --fixup abc1234 # Matches by SHAPitfall 3: Overlapping Fixups
# Problem: Multiple fixups modify same lines
git commit --fixup A # Modifies line 10 in file.py
git commit --fixup A # Also modifies line 10 in file.py
git rebase -i --autosquash
# Conflict during rebase!
# Solution: Resolve conflicts during rebase
# Or combine related changes in single fixup commitAdvanced Integration: Autosquash in Complex Workflows
Autosquash with Git Absorb
Git absorb (external tool) automatically creates fixup commits:
# Install: cargo install git-absorb
# Make changes to multiple files
git add -p # Stage specific changes
# Automatically create fixup commits
git absorb
# Git absorb analyzes staged changes and creates appropriate fixups
# Then run standard autosquash rebase
git rebase -i --autosquashAutosquash in Merge vs Rebase Workflows
Rebase Workflow (standard):
git checkout feature-branch
# Create fixup commits during development
git commit --fixup abc1234
# Before merging to main:
git rebase -i --autosquash main
git checkout main
git merge feature-branch # Fast-forward merge with clean historyMerge Workflow (preserving all commits):
# Even with merge workflow, clean up feature branch first
git checkout feature-branch
git rebase -i --autosquash HEAD~10 # Clean up feature branch itself
# Then merge to main
git checkout main
git merge --no-ff feature-branch # Creates merge commitCI/CD Integration
Pre-merge Hook (ensure clean history):
#!/bin/bash
# .git/hooks/pre-push
# Check if any fixup/squash commits exist
if git log origin/main..HEAD --oneline | grep -E "^[a-f0-9]+ (fixup|squash)!"; then
echo "ERROR: Fixup/squash commits detected!"
echo "Run: git rebase -i --autosquash origin/main"
exit 1
fiGitHub Actions Workflow:
# .github/workflows/validate-commits.yml
name: Validate Commit History
on: [pull_request]
jobs:
check-fixups:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check for unsquashed fixup commits
run: |
if git log origin/main..HEAD --oneline | grep -E "(fixup|squash)!"; then
echo "Found fixup/squash commits that need squashing"
exit 1
fiTroubleshooting Guide
Issue: Autosquash Not Organizing Commits
Symptom: Running git rebase -i --autosquash doesn’t automatically reorder
fixup commits.
Diagnosis:
# Verify fixup commit message format
git log --oneline
# Must see: "fixup! Original commit message"
# Check if commit references correct target
git log --all --oneline | grep "Original commit message"Solutions:
# Solution 1: Verify autosquash is enabled
git config rebase.autosquash
# Should output: true
# Solution 2: Explicitly use --autosquash flag
git rebase -i --autosquash HEAD~10
# Solution 3: Check commit message matching
# Fixup message must exactly match target commit subject lineIssue: Conflicts During Autosquash Rebase
Symptom: Rebase pauses with conflict during autosquash operation.
Resolution Process:
# Conflict occurs during rebase
git status # Shows conflicted files
# Resolve conflicts manually
vim conflicted-file.py # Edit and resolve
# Mark as resolved
git add conflicted-file.py
# Continue rebase
git rebase --continue
# If too complex, abort and retry
git rebase --abort
# Reconsider fixup strategy or resolve conflicts differentlyIssue: Fixup Applied to Wrong Commit
Symptom: Autosquash matched fixup to incorrect target commit.
Cause: Message substring matching found wrong commit.
Prevention:
# Use explicit commit SHA instead of message search
git commit --fixup abc1234 # Unambiguous
# Avoid vague commit messages that might match multiple commits
# Bad: "Fix bug"
# Good: "Fix validation bug in user authentication"Best Practices and Recommendations
Commit Message Discipline
# Good practice: Descriptive, unique commit messages
git commit -m "Implement JWT token validation in AuthService"
git commit -m "Add user role checking to authorization middleware"
# Later fixups are unambiguous:
git commit --fixup :/JWT # Matches first commit
git commit --fixup :/authorization # Matches second commitFixup Early, Fixup Often
# Don't accumulate fixes - create fixups immediately when you discover issues
# This maintains context and makes cleanup easier
# Good workflow:
git commit -m "Add feature" # Commit A
# ... test ...
# Find issue in A
git commit --fixup A # Immediate fixup
# Poor workflow:
git commit -m "Add feature" # Commit A
git commit -m "Add another feature" # Commit B
git commit -m "Add third feature" # Commit C
# ... much later ...
git commit -m "Fix issue in feature from commit A" # Hard to identify targetReview Before Autosquash
# Always review the generated todo list
git rebase -i --autosquash HEAD~10
# Verify:
# 1. Fixups are positioned correctly
# 2. Commit order makes logical sense
# 3. No unexpected commit combinations
# If organization looks wrong, exit without saving and investigateDocument Autosquash Usage in Team
# Team Git Workflow Document
## Using Autosquash for Clean History
1. Enable autosquash globally: `git config --global rebase.autosquash true`
2. During feature development, use `git commit --fixup <commit>` for corrections
3. Before creating pull request, run: `git rebase -i --autosquash main`
4. Review generated todo list and verify organization
5. Push cleaned history for review
## When NOT to Use Autosquash
- After pushing commits to shared branches (coordinate force-push)
- When commit organization is ambiguous
- For emergency hotfixes (keep history explicit)Git autosquash transforms commit cleanup from tedious manual labor into an automated workflow that preserves development velocity while producing professional commit histories. By integrating autosquash into your daily Git practice, you maintain focus on feature development while ensuring your repository history remains clear, logical, and reviewable.