How to Squash Commits in Git
Squashing combines several commits into one clean commit. This tutorial shows three methods (soft reset, interactive rebase, merge --squash), how to push safely with force-with-lease, and what to avoid on shared branches.
Intermediate8 min readUpdated
What does squashing commits mean?
Squashing combines several commits into a single one. The quickest way is git reset --soft HEAD~N followed by a new commit, or git rebase -i HEAD~N and marking the later commits as squash. Rewrites history, so only do it on commits you have not shared.
The short version
- 1Count the commits to combine:
git log --oneline - 2Soft reset:
git reset --soft HEAD~3 - 3Create one commit:
git commit -m "Message" - 4Or use
git rebase -i HEAD~3and mark later commitssquash - 5Push safely:
git push --force-with-lease
Why it matters
Your branch has fifteen commits named 'wip', 'fix typo', and 'try again', and the pull request is about to be reviewed. You want one or two clean commits that tell the story.
Squashing combines several commits into one. It keeps the main history readable, makes reverts simple, and lets reviewers see intent instead of your trial and error.
Where it usually goes wrong
- Squashing commits that were already pushed and shared, then breaking teammates' branches
- Marking every commit as
squashin interactive rebase, including the first one - Losing the commit message while squashing
- Using
git reset --hardinstead of--softand discarding work
Squashing commits, step by step
Step 1: Check which commits to squash
List the recent commits and count how many belong together. They must be consecutive.
Terminalgit log --oneline -8# 9d1c3aa fix typo# 4be7f12 wip# a20c8e3 add search box# 77f0b4d previous work (keep)Tip: Make a safety branch first:
git branch backup/search. If something goes wrong, you can return to it.Step 2: Fastest method: soft reset and recommit
--softmoves the branch back but keeps all changes staged. One new commit then replaces the whole group.Terminal# Squash the last 3 commitsgit reset --soft HEAD~3git commit -m "Add search box"Careful: Use
--soft, never--hard:--hardthrows the changes away.Step 3: Flexible method: interactive rebase
Open the last N commits in an editor. Keep
pickon the first commit and change the others tosquash(keep messages to edit) orfixup(discard messages).Terminalgit rebase -i HEAD~3# In the editor:pick a20c8e3 add search boxsquash 4be7f12 wipfixup 9d1c3aa fix typoTip: The oldest commit is at the top. Never change the first line to
squash: there is nothing before it to combine with.Step 4: Squash everything on a feature branch
To collapse the whole branch into one commit, reset to where it diverged from main.
Terminalgit reset --soft $(git merge-base main HEAD)git commit -m "Add search feature"In Gitoryx: Select consecutive commits on the graph and squash them into oneHow it works Step 5: Squash while merging
git merge --squashapplies a branch's changes as staged edits without creating a merge commit, so you commit them as one.Terminalgit switch maingit merge --squash feature/searchgit commit -m "Add search feature"Tip: GitHub and GitLab offer the same as a 'Squash and merge' button on pull requests.
Step 6: Push the rewritten branch
History changed, so a normal push is rejected. Use
--force-with-lease, which refuses if someone else pushed in the meantime.Terminalgit push --force-with-leaseCareful: Only force-push branches that nobody else is working on. Never force-push
main.
Mistakes to avoid with squashing commits
- Squashing shared history
- Rewriting commits others already pulled forces them to reconcile two versions of the same work.
- Fix: Squash only your own unpushed commits, or a feature branch you own. Use
git revertfor shared history. - Using plain --force
git push --forceoverwrites the remote even if a teammate pushed new commits in the meantime.- Fix: Use
git push --force-with-leaseinstead. - Squashing non-consecutive commits
- Squash combines neighbours. Commits separated by unrelated ones need reordering first.
- Fix: Reorder lines in
git rebase -i, or usegit commit --fixupandgit rebase -i --autosquash.
Squashing commits in Gitoryx
Gitoryx lets you select consecutive commits in the graph and squash them into one with a single action, with a preview of the final message.
- Select consecutive commits on the graph and squash them into one
- Edit the combined commit message before confirming
- See the history before and after, with the backup visible in the reflog
- Force-push safely with lease protection from the push dialog
Free plan · no account required · macOS, Windows and Linux
Squashing commits: frequently asked questions
- How do I squash the last 2 commits?
- Run
git reset --soft HEAD~2thengit commit -m "your message". Or usegit rebase -i HEAD~2and change the second commit tosquash. - What is the difference between squash and fixup?
- Both merge a commit into the previous one.
squashlets you edit the combined message;fixupdiscards the squashed commit's message. - Can I undo a squash?
- Yes, as long as you act soon. Find the old tip with
git reflogand rungit reset --hard <sha>. - Should I squash before merging a pull request?
- It is a good idea when commits are noisy. Many teams use 'Squash and merge' to keep a linear main history with one commit per pull request.
- Does squashing lose my changes?
- No. The final content is identical; only the number of commits and their messages change.
Related reading
- Git Reset: Undo Changes at Any StageTutorial · 10 min
- Git Reflog: Recover Lost Commits and BranchesTutorial · 7 min
- Git Interactive Rebase: A Practical GuideBlog · 19 min