git squash commits is the operation of combining multiple consecutive commits into a single commit using git rebase -i, git reset --soft, or git merge --squash to clean a branch history before merging.
# Interactive rebase – squash last N commits interactively
git rebase -i HEAD~N
Tested on Ubuntu 22.04 with Linux 5.15.x; verify against vendor docs for non-Debian distributions or older kernels.
Syntax
The squash operation is performed via several Git subcommands. The most common patterns are:
# Interactive rebase – squash last N commits interactively
git rebase -i HEAD~N
# Soft reset + new commit – non-interactive squash with concatenated messages
git reset --soft HEAD~N && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
# Merge with squash – combine entire feature branch into one commit on target
git checkout main && git merge --squash feature-branch
# Fixup workflow – auto-squash by marking commits with --fixup
git commit --fixup
git rebase -i --autosquash HEAD~N
Options and Flags
| Flag | Context | Default | Description |
|---|---|---|---|
--soft |
git reset | – | Move HEAD but keep index and working tree unchanged; used before creating a squash commit. |
--hard |
git reset | – | Move HEAD and discard index and working tree changes; dangerous if uncommitted work exists. |
-i |
git rebase | – | Start interactive rebase, opening editor to mark commits as pick/squash/fixup. |
--squash |
git merge | – | Merge as a single squash commit, staging changes without creating a merge commit. |
--fixup |
git commit | – | Create a commit intended to be squashed into a previous commit; subject line starts with “fixup!”. |
--autosquash |
git rebase -i | off | Automatically reorder fixup!/squash! commits to squash into their target. |
--autostash |
git rebase | off | Automatically stash/unstash dirty working tree before/after rebase. |
--continue |
git rebase | – | Resume rebase after resolving conflicts. |
-m |
git commit | – | Use provided string as commit message. |
--edit |
git commit | – | Open editor to modify the commit message. |
--format=%B |
git log | – | Print only the raw commit message body; used in message extraction. |
--reverse |
git log | – | Output commits in chronological order (needed for concatenated message). |
Usage Examples
1. Squash last 3 commits with full message concatenation
# Non-interactive: reset soft, then commit with combined messages
git reset --soft HEAD~3 && git commit --edit -m"$(git log --format=%B --reverse HEAD..HEAD@{1})"
Preserves the index (staged changes) from the three commits and creates a single new commit whose message is the concatenation of all three original messages in chronological order. Useful in CI pipelines or scripts where interaction is not possible. Note: HEAD@{1} refers to the previous HEAD position; after reset --soft, it points to the first squashed commit. Requires Git 1.7+ for the --format syntax.
2. Interactive rebase to squash last 5 commits with custom message
git rebase -i HEAD~5
# In the editor, change 'pick' to 'squash' (or 's') for all but the first line.
# Save and close, then write the new commit message.
Gives full control over which commits to squash and the final message. The rebase replays commits; if conflicts occur, Git pauses, the user resolves them, then runs git rebase --continue. Best for feature branches before merging to main. To abort, use git rebase --abort.
3. Auto-squash fixup commits using --fixup and --autosquash
# After initial commit, mark each subsequent fix with --fixup
git commit --fixup
# Later, rebase with autosquash to squash the fixups
git rebase -i --autosquash HEAD~10
Eliminates manual reordering during interactive rebase. Each fixup commit is automatically placed directly after the target commit and marked as fixup (squash but discard message). Ideal for code review feedback loops where you want a clean history before merging. Ensure --autosquash is used with an interactive rebase; it reorders the todo list based on the subject prefix.
Troubleshooting & Common Errors
| Error Message / Symptom | Root Cause | Resolution Command |
|---|---|---|
Cannot 'squash' without a previous commit |
You marked the first commit as squash in rebase editor |
Ensure the first commit remains pick; use git rebase --abort and restart |
fatal: Needed a single revision --invalid HEAD~N |
N exceeds total commits on current branch |
Check commit count with git log --oneline | wc -l and use a smaller N |
Your branch and 'origin/main' have diverged |
Squash was performed on already-pushed commits | Use git push --force-with-lease only if you own the branch; coordinate with the team |
nothing to commit, working tree clean after reset --soft |
HEAD~N pointed to the same commit as the current HEAD (i.e., N=0) |
Verify git log --oneline and run git diff --cached to confirm changes exist |
Conflicts during git rebase -i |
Two squashed commits modified the same lines | Resolve manually, git add <file>, then git rebase --continue |
Platform Comparison (Squash Merge Behavior)
| Platform | Approach | CLI Equivalent / UI Option |
|---|---|---|
| GitHub | PR “Squash and merge” button | Performs git merge --squash on the server |
| GitLab | “Squash commits” checkbox in MR | Rebases branch with -i and optionally squashes |
| Azure Repos | “Squash changes” in PR completion | Uses git merge --squash or custom strategy |
| Bitbucket | “Squash” option in PR merge | Rebase + squash or git merge --squash |
| Local Git | Manual git rebase -i or reset --soft |
Full control; no cloud-specific subcommand |
Note: All cloud platforms implement squash as a server-side merge strategy. There is no direct cloud CLI equivalent for the local git squash commits operation; it must be performed inside a compute instance or local clone.
Frequently Asked Questions
What is the difference between git rebase -i (squash) and git merge –squash?
Answer: git rebase -i HEAD~N rewrites commit history interactively; git merge --squash creates a single squashed commit on the current branch without altering the source branch history. Use rebase for feature cleanup; merge –squash for incorporating stable branch changes.
When should I use the –autosquash flag in git rebase?
Answer: Use –autosquash when you have pre-staged fixup! or squash! commits to automatically fold them during interactive rebase. Create fixup commits with git commit --fixup , then run git rebase -i --autosquash . This reorders the todo list, collapsing fixup commits into their targets. Saves manual reordering for clean history management.
How do I fix “error: could not apply” when squashing commits during git rebase -i?
Answer: Resolve merge conflicts manually, stage fixes with git add, then run git rebase –continue. The error indicates a conflict when applying a squashed commit. Inspect conflicted files with git status, edit to resolve, git add , then git rebase --continue. Use git rebase --abort to revert if resolution fails.
Does git squash via interactive rebase work on GitHub Actions, GitLab CI, and Bitbucket Pipelines?
Answer: Yes, all three CI platforms support git interactive rebase as long as git version >= 2. Pipelines run with default git installations. For headless environments, set git config user.email and user.name before rebase. Note: remote branch pushes after rebase require --force-with-lease to avoid overwriting others’ work.
What is the fastest way to squash the last N commits without interactive editor?
Answer: Use git reset --soft HEAD~N && git commit -m "squashed commit" for immediate, non-interactive squash of the last N commits. This resets the branch pointer back N commits while keeping changes staged, then a single new commit captures all changes. No rebase or editor interaction required.
git reset --soft HEAD~3 && git commit -m "Feature X implementation"

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.