How to Squash Commits Before Opening a Pull Request

Tested by TNT Review — record TNT-TEST-2026-10-05-016, 5 October 2026. We ran these exact commands in a real local git repository with 3 messy commits, and the real before/after result is in Verification.

The problem

“WIP,” “fix typo,” “actually fix typo” — a real working history, full of small fix-up commits, is normal while you’re building something. Opening a pull request with that exact history visible makes the reviewer read through your mistakes instead of your finished change.

Expected outcome

By the end of this guide you will know how to combine several messy commits into one clean commit, with all the same file changes, before you open a pull request.

Requirements and costs

  • Git, already installed if you’re using GitHub at all.
  • Cost: free.

Unfamiliar terms, explained

  • Squash — combining multiple commits into one, keeping their combined file changes but discarding their individual history.
  • git reset --soft — moves your branch pointer back without touching your actual files, so everything you “undo” is still sitting there, staged and ready to commit again.

Step-by-step implementation

  1. Check how many commits you want to combine with git log --oneline.
  2. Move your branch back that many commits, without touching your files:
    git reset --soft HEAD~3

    (replace 3 with your real count)

  3. Commit everything as one clean commit:
    git commit -m "A clear description of the whole change"
  4. Push. If you’d already pushed the messy commits earlier, you’ll need git push --force-with-lease to overwrite them — only do this on a branch you own, never on a shared branch others have already built on.

A real example

Before, git log --oneline showed:

86e3e1e WIP: actually fix typo
51091e1 WIP: fix typo
c0472d5 WIP: start feature

After git reset --soft HEAD~2 and one new commit:

da1b1a5 Add feature with typo fix
c0472d5 WIP: start feature

with the file’s actual content exactly as it was before — squashing combines history, it does not touch your files.

Verification and troubleshooting

What we tested, on 5 October 2026 (record TNT-TEST-2026-10-05-016): created a real local git repo with 3 commits (“WIP: start feature,” “WIP: fix typo,” “WIP: actually fix typo”), ran git reset --soft HEAD~2 followed by one new commit, and confirmed the log now showed exactly 2 commits with the new one combining the two WIP fixes — and confirmed the file’s actual content (all 3 lines) was identical before and after, proving no data was lost.

Troubleshooting:

  • “fatal: ambiguous argument ‘HEAD~3’.” You’re trying to go back further than the branch has commits — check your real count with git log --oneline first.
  • You already pushed the messy commits. After squashing locally, you must force-push to overwrite the remote history — use --force-with-lease, not plain --force, so it fails safely if someone else pushed in the meantime.
  • Other people have already pulled your branch. Squashing rewrites history; anyone who already has the old commits will hit conflicts. Only squash branches you haven’t shared widely yet, ideally before you open the pull request, not after others have reviewed it.

Limitations and alternatives

GitHub’s own “Squash and merge” button does this automatically when a pull request is merged, with no local git commands needed — a fine default if you don’t need a clean history until merge time. The manual approach here is for when you want the clean commit visible to reviewers before they even look at the PR, not just after merging.

Is there a paid version?

Not applicable. This is a free, built-in git feature, not a product.

Leave a comment