Git

What Is Git Squash? Clean Up Your Commits

What Is Git Squash? Clean Up Your Commits

Twelve commits on a feature branch and half of them say “WIP.” Sound familiar? That’s exactly the problem git squash solves.

Git squash combines multiple commits into a single, clean commit before merging into your main branch. It keeps your commit history readable instead of cluttered with typo fixes and half-finished thoughts.

This article breaks down what git squash actually does, how it works through interactive rebase and merge, when to use it (and when not to), and the common mistakes that trip up even experienced developers. You’ll also learn how platforms like GitHub and GitLab handle squashing in pull request workflows, plus best practices for keeping your team’s Git history useful.

What is Git Squash

maxresdefault What Is Git Squash? Clean Up Your Commits

Git squash is the process of combining multiple commits into a single commit. It takes a series of individual changes on a feature branch and collapses them into one clean entry in your commit history.

There’s no standalone git squash command. Squashing is a technique you perform through interactive rebase or a merge option, not a dedicated operation in the Git CLI.

Say you’ve got 12 commits on a feature branch. Half of them say “WIP” and two are typo fixes. Squashing lets you roll all of that into one commit with a meaningful message before it hits main.

The resulting commit contains every change from the original commits. Your code doesn’t lose anything. The individual commit objects become unreachable in the reflog but aren’t immediately deleted by Git’s garbage collector.

GitHub now hosts over 180 million developers globally, according to the Octoverse 2025 report. With that scale of collaboration, keeping commit history readable isn’t a luxury. It’s a practical requirement for teams working across branches and pull requests.

The concept is simple: fewer, better commits on your main branch. The execution depends on whether you use git rebase -i or git merge --squash, which we’ll break down next.

How Git Squash Works

maxresdefault What Is Git Squash? Clean Up Your Commits

Squashing happens through two paths. Both produce the same result (multiple commits collapsed into one), but they work differently under the hood.

Why is GitHub the heart of open source?

Uncover GitHub statistics: developer community growth, repository trends, collaboration patterns, and the platform that powers modern software development.

Explore GitHub Data →

Interactive Rebase with Squash

This is the approach most developers reach for. You run git rebase -i HEAD~n, where n is the number of commits you want to work with.

Git opens your text editor with a list of those commits. Each line starts with the word pick. To squash, you change pick to squash (or just s) on every commit you want to fold into the one above it.

The keywords matter:

  • squash (s): combines the commit with the previous one and lets you edit the combined commit message
  • fixup (f): same as squash, but silently discards the commit message from the squashed commit

After you save and close the editor, Git replays the commits and presents a new editor window for your final commit message. That’s where you write something useful instead of “WIP part 3.”

Hutte research found that nearly 90% of developers have dealt with merge conflicts at some point. Interactive rebase can trigger these conflicts too, especially when squashing commits that touch overlapping lines. You’ll need to resolve them manually before the rebase can continue.

Looking to sharpen your Git skills? Branching, merging, rebasing, and everything else you need - including git rebase, git stash, and commit workflows - is on one page in the Git Cheat Sheet.

Squash Merge onto a Branch

The second approach uses git merge --squash. This takes all commits from a source branch and stages them as a single set of uncommitted changes on your current branch.

You then commit those changes yourself with one message. The source branch stays untouched.

Key difference from interactive rebase: this method doesn’t rewrite history on the source branch. It creates a brand-new commit on the target branch. That makes it safer for branches that other people are also working on.

Azure DevOps, GitHub, and GitLab all surface this as a one-click option when you close a pull request. We’ll cover that in more detail in the pull request workflows section.

Git Squash vs. Git Merge vs. Git Rebase

maxresdefault What Is Git Squash? Clean Up Your Commits

These three operations all get changes from one branch into another. But they leave very different footprints in your git log.

StrategyCommit HistoryBest ForTradeoff
MergePreserves all individual commits + merge commitShared branches, open-source projectsHistory gets cluttered with merge commits
RebaseReplays commits linearly, no merge commitLocal feature branches, linear workflowsRewrites commit hashes (dangerous on shared branches)
Squash mergeSingle commit on target branchPR completion, feature integrationLoses granular commit-level detail

A standard git merge keeps everything. Every “fix linting” and “oops forgot semicolon” commit stays visible. It also adds an extra merge commit, which can make debugging with git bisect harder on active branches.

Rebase moves your commits to the tip of the target branch, creating a straight line of history. Clean, but it rewrites SHA hashes. If you rebase a branch someone else has pulled, you’ll break their local copy.

Squash merging falls somewhere in between. You get one clean commit on main, but you lose the step-by-step development story. Mitchell Hashimoto, co-founder of HashiCorp, put it well in a widely shared GitHub Gist: he prefers merge commits because they make git bisect actually useful. Landing on a squashed +2000/-500 commit during a bisect isn’t helpful. Landing on a focused +50/-50 commit is.

There’s no universally correct answer here. Your mileage may vary depending on team size, code review practices, and how much you care about tracing individual changes after the fact.

When to Use Git Squash

maxresdefault What Is Git Squash? Clean Up Your Commits

Squashing makes sense in specific situations. It’s not something you should apply as a blanket rule to every branch.

Good candidates for squashing:

  • Feature branches with a pile of “WIP,” “fix typo,” and “testing something” commits that add noise but no context
  • Pull requests headed for review where a clean, readable history helps reviewers focus on the actual change
  • Open-source contributions where maintainers expect (or require) a single commit per feature
  • Short-lived branches with small diffs that tell one clear story

According to the Kluster.ai Developer Guide, roughly 60% of developers now use squash and merge regularly as part of their workflow, based on 2023 Stack Overflow survey data. Still, over 35% of teams stick with traditional merge commits, which says a lot about how context-dependent this choice is.

When squashing can hurt:

If your branch has 50 commits spread across multiple logical changes, squashing everything into one giant commit defeats the purpose. You lose the ability to revert a specific commit or trace when a bug was introduced.

Took me a while to learn that lesson. I used to squash everything before merging, thinking a clean log was always better. Then I needed to bisect a regression buried inside a 400-line squashed commit and, well, that changed my approach pretty fast.

How to Squash Commits Step by Step

maxresdefault What Is Git Squash? Clean Up Your Commits

Two methods. Both work. Pick the one that fits your situation.

Squashing with Interactive Rebase

Step 1: Make sure your feature branch is up to date with the target branch.

Step 2: Run the interactive rebase command. If you want to squash the last 4 commits:

git rebase -i HEAD~4

Step 3: Your editor opens with something like this:

pick a31f2d7 Add login form layout pick 4e8b1c9 Fix button alignment pick b9c5f3e Remove console.log pick f1d6a0b Add input validation `

Step 4: Keep the first commit as pick. Change the rest to squash (or s):

` pick a31f2d7 Add login form layout squash 4e8b1c9 Fix button alignment squash b9c5f3e Remove console.log squash f1d6a0b Add input validation `

Step 5: Save and close. Git opens another editor where you write your final commit message. Make it count.

If conflicts come up during the rebase, Git will pause and ask you to resolve them. Fix the files, stage them with git add, then run git rebase –continue.

Squashing with Merge

This one’s simpler if you just want to bring a branch’s changes into main as a single commit.

Switch to your target branch:

git checkout main

Run the squash merge:

git merge –squash feature-branch

Commit the result:

git commit -m “Add user login feature”

That’s it. All changes from the feature branch are now a single commit on main. The feature branch itself isn’t modified.

One thing that trips people up: after a squash merge, Git doesn’t record the merge relationship between branches. So if you keep working on the same feature branch and try to squash merge again later, you’ll likely run into conflicts from commits that were already applied. Delete the source branch after squashing, or you’ll have a headache on your hands.

Git Squash in Pull Request Workflows

maxresdefault What Is Git Squash? Clean Up Your Commits

Most teams don’t squash from the command line anymore. They click a button.

GitHub, GitLab, and Bitbucket all support squash merging directly in the pull request (or merge request) interface. This has made the technique way more accessible, even for developers who aren’t comfortable with interactive rebase.

How Platforms Handle Squash Merging

PlatformSquash OptionConfiguration
GitHub“Squash and merge” button on PRsRepo settings → Allow squash merging
GitLabCheckbox in merge request settingsCan be set as default per project
BitbucketSquash merge option during PR completionConfigurable in repository settings
Azure DevOps“Squash commit” toggle in PR completion dialogBranch policies can enforce it

GitHub’s Octoverse 2025 report showed that developers pushed nearly 1 billion commits in 2025, a 25% year-over-year increase. Monthly pull request merges averaged 43.2 million, up 23% from the previous year. With that volume, squash merging at the platform level removes friction that would otherwise slow teams down.

Team Policies Around Squashing

Some teams enforce squash-only merging through branch protection rules. Others leave it as an option and let individual developers decide per PR.

The MediaWiki project on GitLab, for example, enables squash by default on all merge requests. Their rationale: it cuts cognitive overhead for developers who should focus on the content of their merge requests, not on crafting a perfect commit history during active development.

But enforcing squash-only has a cost. It removes the ability to preserve meaningful intermediate commits when a PR contains multiple logical changes. Graphite’s engineering blog recommends matching your merge strategy to the type of work: squash for prototypes and experiments, merge commits for open-source libraries, and trunk-based development with small stacked PRs for fast-moving teams.

Your git workflow should reflect how your team actually works, not some theoretical ideal. If your developers already write atomic commits, forcing squash on top of that just throws away good information.

A continuous integration setup benefits directly from squash merging. Every push to main becomes a single, atomic commit representing one complete feature. That creates a clean relationship between a merge and a build pipeline run, making it straightforward to trace which deployment caused an issue in your production environment.

Common Mistakes When Squashing Commits

Squashing is straightforward until it isn’t. Most of the problems developers run into come from applying the technique in the wrong context or skipping a step they didn’t think mattered.

Squashing Commits on a Shared Branch

maxresdefault What Is Git Squash? Clean Up Your Commits

This is the biggest one. Squashing rewrites commit history, which changes the SHA hashes of every affected commit.

If you squash commits on a branch that other developers have already pulled, their local copies will reference commits that no longer exist on the remote. The next time they try to pull or push, Git won’t know how to reconcile the two histories.

The fix usually involves a force push, which overwrites the remote branch entirely. GitHub’s own documentation warns that force pushing can remove commits other collaborators based their work on, leading to corrupted pull requests.

Rule of thumb: only squash commits on branches that belong to you alone. If anyone else has checked out that branch, don’t rewrite its history.

Losing Context by Over-Squashing

Hutte research shows 85% of developers say Git improved their team’s collaboration. But squashing everything into mega-commits can undo that benefit.

A branch with 30 commits across three logical changes shouldn’t become one commit. That destroys the ability to revert a specific change without touching the others.

Better approach: use interactive rebase to group related commits together while keeping separate logical changes as distinct commits. Three clean commits are almost always better than one giant blob.

Merge Conflicts During Rebase

Research from Ghiotto et al. found that 8% to 21% of merge trials in open-source projects fail due to conflicts. Interactive rebase can hit these same conflicts, and they show up one commit at a time.

Each commit being replayed might trigger its own conflict. You resolve one, run git rebase –continue, and immediately hit another. On a branch with many commits, this gets old fast.

Practical tip: if a rebase gets messy, git rebase –abort brings you back to where you started. No harm done. You can try again or switch to git merge –squash instead, which handles all conflicts in a single pass.

Repeating Squash Merges on Long-Lived Branches

After a squash merge, Git doesn’t record the merge relationship between branches. The remote repository has no idea the changes already landed.

If you keep the source branch alive and try to squash merge again later, you’ll see conflicts from commits Git thinks haven’t been applied yet. Delete the feature branch after squashing, or create a fresh one from main.

Git Squash and Commit History Best Practices

maxresdefault What Is Git Squash? Clean Up Your Commits

Squashing is a tool. Like any tool, it works best when you match it to the job instead of using it for everything.

Granular History vs. Clean History

ApproachAdvantageDisadvantage
Keep all commitsFull development context preservedNoisy log with WIP and typo-fix entries
Squash everythingClean, one-commit-per-feature historyHarder to bisect, revert, or trace changes
Selective squashingReadable history with meaningful granularityRequires discipline and rebase knowledge

Mitchell Hashimoto’s widely referenced take: squash makes sense for branches with a pile of WIP commits and a small diff. But for larger features, preserving individual commits (each one buildable) gives you far better debugging capabilities.

The git diff between approaches shows up most clearly when something breaks in production and you need to isolate exactly what caused it.

How Squashing Affects git bisect

git bisect uses binary search to find the exact commit that introduced a bug. With 1,000 commits, it takes about 10 tests to narrow down the culprit. That's the power of O(log n) complexity.

But bisect only works well when each commit is small and focused. If you’ve squashed 40 commits into one +2,000 line change, bisect points you at that single commit and you’re back to reading through hundreds of lines manually.

Teams that rely on bisect for debugging (the Linux kernel project is a well-known example) tend to avoid aggressive squashing. They prefer clean, atomic commits where every commit compiles and passes tests.

Conventional Commits and Squashing

The Conventional Commits spec adds structured prefixes to commit messages: feat:, fix:, docs:, refactor:, and so on.

This structure enables automated changelog generation and semantic versioning. Tools like semantic-release parse your commit history to determine whether the next release is a patch, minor, or major bump.

Squashing interacts with this in a specific way. If you squash five commits into one, that single commit’s message needs to follow the convention. The default squash message (a concatenation of all original messages) usually doesn’t. You’ll need to rewrite it manually.

Good habit: when you squash and merge a PR, always rewrite the commit message to follow your team’s convention. Something like feat(auth): add JWT-based login flow tells the whole story in one line.

Team Agreements on Squashing

The Octoverse 2025 report showed over 36 million new developers joined GitHub in the past year alone. With teams growing and distributed work becoming the default, having explicit agreements about commit strategy matters more than it used to.

What to agree on:

  • Default merge method for PRs (squash, merge commit, or rebase)
  • When exceptions are allowed (large PRs with multiple logical changes)
  • Commit message format after squashing

Graphite’s engineering blog recommends matching the strategy to the type of work. Prototypes and experiments get squashed. Open-source libraries keep full merge history. Fast-moving teams on git flow or similar branching models might mix approaches depending on the branch type.

The source control management strategy should serve the team, not the other way around. If your code review process already catches issues before merge, heavy squashing might just be removing useful information that nobody was confused by in the first place.

Whatever you pick, document it. Add it to your project documentation or CONTRIBUTING.md so every new contributor knows the expectation on day one. A software development plan that covers version control conventions saves everyone from the “wait, how do we merge here?” conversation three months into the project.

FAQ on What Is Git Squash

Is git squash a standalone command?

No. There’s no dedicated git squash command in Git. Squashing is performed through interactive rebase (git rebase -i) or by using git merge –squash. Both approaches combine multiple commits into one, just through different workflows.

What is the difference between squash and fixup?

Both combine commits during interactive rebase. Squash lets you edit the combined commit message. Fixup silently discards the message from the folded commit and keeps only the first one. Use fixup for quick cleanup without editing.

Does squashing delete my code changes?

No. Squashing only changes the commit history, not your actual code. Every line of code from the original commits ends up in the new single commit. The changes are preserved. Only the individual commit entries disappear from the log.

Can I squash commits after pushing to a remote branch?

Yes, but you’ll need a force push afterward because squashing rewrites commit history. Only do this on branches nobody else has pulled. Use git push –force-with-lease as a safer alternative to avoid overwriting a teammate's work.

What happens to squashed commits?

The original commits become unreachable in Git’s object database. They aren’t deleted immediately. Git’s garbage collector removes them eventually. Until then, you can recover them through git reflog if something goes wrong.

Should I always squash before merging?

Not always. Squash when your branch has noisy WIP commits that add no value. Skip squashing when individual commits represent distinct logical changes. The right choice depends on your team’s workflow and how you use tools like git bisect.

How do GitHub and GitLab handle squash merging?

Both platforms offer a built-in “squash and merge” option when completing a pull request or merge request. Repository admins can set it as the default or enforce it through branch protection rules. No command line needed.

What is git merge –squash?

git merge –squash takes all commits from a source branch and stages them as a single set of uncommitted changes on the target branch. You then create one new commit manually. The source branch history stays untouched.

Can squashing cause merge conflicts?

Yes. During interactive rebase, Git replays each commit individually. If commits touch overlapping lines, conflicts can appear at each step. The alternative, git merge –squash, handles all conflicts in a single pass, which is often simpler.

How many commits should I squash at once?

There’s no fixed limit. Squash as many as make sense for one logical change. A feature with 15 “fix typo” and “WIP” commits is a good candidate. A branch with 50 commits across multiple features should probably stay as separate, clean commits.

Conclusion

Understanding what is git squash comes down to one practical skill: knowing when to condense your commit history and when to leave it alone. It’s not complicated, but it does require judgment.

Squashing through interactive rebase gives you fine control over how commits get combined. The squash merge option on platforms like GitHub, GitLab, and Bitbucket makes it even simpler during pull request workflows.

But don’t treat it as a default for every branch. Aggressive squashing can hurt your ability to debug with git bisect or revert specific changes when something breaks in production.

Match the strategy to the situation. Use squash for noisy feature branches. Keep granular commits when traceability matters. Document your team’s convention so everyone stays aligned.

The best commit history is one your team can actually use six months from now.

50218a090dd169a5399b03ee399b27df17d94bb940d98ae3f8daff6c978743c5?s=250&d=mm&r=g What Is Git Squash? Clean Up Your Commits

Stay sharp. Ship better code.

Every week: one curated article, one tool worth knowing, one tip you can use tomorrow. No noise, no padding.