Skip to main content

How to squash commits

· 6 min read
Serhii Hrekov
software engineer, creator, artist, programmer, projects founder

Squashing commits is a common Git operation that combines multiple commits into a single, cleaner commit. This is crucial for keeping your branch history tidy before merging into a main branch (like main or master), making the project history easier to read and revert [1].

The primary tool for squashing commits is interactive rebase (git rebase -i).

Prerequisites

  1. Safety First: Ensure your repository is clean.

    git status

    If you have any uncommitted changes, stash or commit them before starting.

  2. Determine the Target: Identify the commit before the first commit you want to squash. This is your target commit.


Step 1: Start the Interactive Rebase

You initiate the interactive rebase command by specifying the target commit. Everything after this commit will be included in the rebase editor.

A. Squashing the Last N Commits

If you want to squash the last 3 commits, use HEAD~3:

git rebase -i HEAD~3

B. Squashing Commits Up to a Specific SHA

If you want to squash all commits made since commit a1b2c3d:

git rebase -i a1b2c3d

Step 2: Edit the Interactive Rebase File

Git will open a text editor (usually Vim or your default editor) containing a list of the commits you selected, ordered from oldest (top) to newest (bottom).

Initial Editor Content Example:

pick e4f5g6h Commit 1: Fix typo in header
pick h7i8j9k Commit 2: Add new feature logic
pick l0m1n2o Commit 3: Cleanup and documentation
# ... (instructions below) ...

You need to change the command next to the commits you want to combine.

CommandActionDescription
pick (default)KeepKeeps the commit and uses it as the base for the operation. Keep this for the oldest commit.
squash (s)CombineCombines this commit's changes into the previous (above it) commit.
fixup (f)Combine & DiscardCombines this commit's changes into the previous commit, but discards its commit message.

Modified Editor Content Example (Squashing Commits 2 and 3 into Commit 1):

pick e4f5g6h Commit 1: Fix typo in header
squash h7i8j9k Commit 2: Add new feature logic
fixup l0m1n2o Commit 3: Cleanup and documentation
  • The changes from h7i8j9k and l0m1n2o will be merged into e4f5g6h.
  • The message for l0m1n2o will be thrown away (fixup).
  • The messages for e4f5g6h and h7i8j9k will be combined in the next step.

Save and close the editor.


Step 3: Write the New Commit Message

After closing the first editor, Git will open a second editor (if you used at least one squash command) to prompt you for the new, unified commit message.

Second Editor Content Example:

# This is a combination of 2 commits.
# The first commit's message is:
Commit 1: Fix typo in header

# The second commit's message is:
Commit 2: Add new feature logic
  1. Delete the old messages and write a single, clear, descriptive message for the new, combined commit.
  2. Save and close this second editor.

Step 4: Force Push (If Necessary)

If the commits you squashed were already pushed to a remote branch, you have rewritten history. The local branch history no longer matches the remote branch history.

You must use a force push to overwrite the remote history. Use the safe force push option (--force-with-lease) to prevent overwriting someone else's recent work [2].

# ONLY use this command if you have already pushed the commits before squashing!
git push --force-with-lease origin <your-branch-name>

If the squashed commits were local and never pushed, use a standard push:

git push origin <your-branch-name>

Sources

  1. Git Documentation on Rewriting History
  2. Atlassian - Git Interactive Rebase
  3. Git Push --force-with-lease vs. --force