Skip to main content
Infrastructure as Code (IaC) Cheat Sheets

Git Squash Commits: Syntax, Flags, Examples & Troubleshooting

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"

See also  Define PBX: CLI Cheat Sheet with Verified Cisco & Asterisk