Course contents

Squash multiple commits into one

Sign in to run this lab and save your progress

Learn

While you're building a feature, you probably make lots of small in-progress commits: "WIP", "actually try this", "fix that typo from earlier", and so on. Useful during the work, embarrassing to share. Before merging back to main, most people collapse those throwaway commits into one clean commit that describes the whole feature.

That collapse is called squashing, and there are two ways to do it. This lesson shows the simpler one.

The soft reset technique

The recipe:

git reset --soft HEAD~3
git commit -m "Implement feature"

Two commands, one clean commit. Here's what each does:

git reset --soft HEAD~3 moves the branch pointer back 3 commits, but keeps all the file changes staged. Nothing on disk changes. The three commits' file changes are now all sitting in the staging area, waiting for a new commit.

git commit -m "Implement feature" creates a single new commit containing everything that was staged. The three WIP commits are gone from your branch history; one clean commit takes their place.

The number after HEAD~ is how many commits to reset back over. If you had 5 WIP commits, you'd use HEAD~5. Count carefully: reset back to the commit BEFORE your first WIP, not to the WIP itself.

Why --soft

git reset has three modes, and the mode determines what happens to your changes:

  • --soft moves HEAD, keeps everything staged. What we want here.
  • --mixed (the default) moves HEAD, keeps changes but unstages them.
  • --hard moves HEAD and throws away every change.

--soft is the right choice for squashing because it preserves the file content as staged changes ready for one big commit. If you use --mixed you'd need to re-stage manually. If you use --hard you'd lose the work.

The interactive rebase alternative

The other way to squash uses git rebase -i:

git rebase -i HEAD~3

Git opens an editor with your three commits listed:

pick c2 WIP 1
pick c3 WIP 2
pick c4 WIP 3

Change pick to squash (or s) on the second and third:

pick c2 WIP 1
squash c3 WIP 2
squash c4 WIP 3

Save, close the editor, and Git combines them, opening the editor again for the final message. More steps, more editor invocations, but you can reorder or drop commits at the same time.

For "just squash these three into one", --soft reset is cleaner. For anything more complicated (reorder, edit an earlier commit, drop one commit while keeping others), reach for rebase -i.

Squash before you push

Both techniques rewrite history, so both are subject to the "don't rewrite shared commits" rule. In practice this is easy: squash your feature branch just before you open a pull request. Once the PR is up and others are looking at the branch, the commits are effectively public and you shouldn't reshape them.

Some hosting platforms (GitHub, GitLab) also offer a "squash and merge" option that squashes the whole PR into one commit when it lands on main. If your team uses that setting, you don't need to squash locally at all: the platform does it for you. Ask what your team's convention is; different projects handle this differently.

Your task

You made three WIP commits while figuring something out (WIP 1, WIP 2, WIP 3) on top of an Initial commit. Before sharing, collapse those three into a single commit titled Implement feature, containing all the same file changes. After this, the repository should have two commits: Initial and Implement feature.