How do you squash multiple commits into one in Git?

Use interactive rebase (git rebase -i) to combine several WIP commits into a single, clean commit before merging.

GitVersion Control

Overview

Squashing combines multiple commits into one. It is common to commit frequently while working ("WIP", "fix typo", "actually fix it") and then squash everything into a single meaningful commit before a PR merge. Interactive rebase is the tool for this.

Key Points

  • •`git rebase -i HEAD~N` opens an editor showing the last N commits.
  • •Change `pick` to `squash` (or `s`) on commits you want to merge into the one above.
  • •After squashing, Git opens a second editor to combine/edit the commit messages.
  • •Only squash commits that have NOT been pushed to a shared branch.
  • •`git merge --squash` is an alternative: merges a branch into the staging area as a single commit.

Examples

Squash last 4 commits interactively

bash
git rebase -i HEAD~4

# Editor opens showing:
# pick a1b2c3d WIP: start login form
# pick b2c3d4e add validation
# pick c3d4e5f fix typo
# pick d4e5f6g style form

# Change to:
# pick a1b2c3d WIP: start login form
# squash b2c3d4e add validation
# squash c3d4e5f fix typo
# squash d4e5f6g style form

# Save → second editor opens to write the final combined message

The top commit stays as "pick"; all others become "squash" to merge up into it.

Squash with a preset message (no editor for messages)

bash
git rebase -i HEAD~4
# Use "fixup" instead of "squash" to discard the message of each squashed commit
# pick a1b2c3d feat: login form
# fixup b2c3d4e add validation
# fixup c3d4e5f fix typo

"fixup" merges the commit but silently discards its message.

Squash a whole branch on merge

bash
git switch main
git merge --squash feature/login
git commit -m "feat: add login form with validation"

Merges all branch commits into a single staged change. You write the final commit message yourself.

Pro Tip

Many teams configure GitHub/GitLab to "Squash and merge" PRs automatically. This keeps the main branch history clean (one commit per PR) without requiring manual interactive rebases.