How to squash commits
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
-
Safety First: Ensure your repository is clean.
git statusIf you have any uncommitted changes, stash or commit them before starting.
-
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.
| Command | Action | Description |
|---|---|---|
pick (default) | Keep | Keeps the commit and uses it as the base for the operation. Keep this for the oldest commit. |
squash (s) | Combine | Combines this commit's changes into the previous (above it) commit. |
fixup (f) | Combine & Discard | Combines 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
h7i8j9kandl0m1n2owill be merged intoe4f5g6h. - The message for
l0m1n2owill be thrown away (fixup). - The messages for
e4f5g6handh7i8j9kwill 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
- Delete the old messages and write a single, clear, descriptive message for the new, combined commit.
- 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>
