Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Squashing Git Commits Locally without Rebasing or Merging a Branch

blog/cards/squashing-git-commits-locally-without-rebasing-or-merging-a-branch.jpg

This could be useful to locally rewrite history before pushing your changes up or before making a pull request.

Quick Jump: Demo Video

After years of using git I feel like I only use the tiniest fraction of git’s features. Recently I started to use git to create temporary local save points while exploring how I might want to implement something instead of leaving tons of temporary comments or copy / pasting backup files.

This translates to making a bunch of throw away commits that contain the state of the code at that specific point in time. Often times I don’t care about making this message really good so I’ll use commit messages like “avatar, working file preview”. I may end up with half a dozen of these or more in a coding session.

The idea here is once I’m happy with how things turned out and I’m ready to push up the real version I’ll squash these commits into a single good commit message. Technically it’s not a squash but it is giving the same effect – often times the desired effect of “combine all of these throw away commits into 1 new commit”.

Here’s one way to quickly do this and the video below demonstrates all of this too.

Create the example repo
mkdir -p /tmp/git-squash \
  && cd $_ \
  && git init \
  && touch README.md a b c \
  && git add README.md && git commit -m "Initial commit" \
  && git add a && git commit -m "Add 'a' file" \
  && git add b && git commit -m "Add 'b' file" \
  && git add c && git commit -m "Add 'c' file"

I’ve done a video in the past about that cd $_ command. It will cd into the last argument of the last run command.

Get a list of commits to figure out what you want to squash together
git log
commit 246224b2cb5ed174d2d3c9cd0a76f643c44bf950 (HEAD -> master)
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:37:21 2022 -0400

    Add 'c' file

commit 965022d604dc79605c49121de04d9e80688656a7
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:37:14 2022 -0400

    Add 'b' file

commit 78eb36c01ccbbe3ac2d251f7729052c41d6b1e23
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:37:07 2022 -0400

    Add 'a' file

commit b8fcd644b447d4022ba0910a749d130b42d99362
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:36:50 2022 -0400

    Initial commit
Find the bottom most commit you want to “squash” into
# Let's say we want to use this commit:
commit 78eb36c01ccbbe3ac2d251f7729052c41d6b1e23
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:37:07 2022 -0400

    Add 'a' file
Perform a soft git reset on this commit
# The caret at the end is very important:
git reset --soft 78eb36c01ccbbe3ac2d251f7729052c41d6b1e23^

This isn’t going to modify your working tree, A.K.A. this won’t cause your changes to be lost on disk. We’ll verify that next too.

Verify the state of things with a git status
git status
On branch master
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   a
        new file:   b
        new file:   c

Everything is staged and ready to be commit.

Make your new good single commit message
git commit -m "Add files"

You’re not limited to 1 commit here too.

Since things have been reset you have free reign on how you want to commit these files. You could decide to make 3 really good commit messages or just 1. It’s up to you, there’s no right or wrong choice here. It depends on the feature and your style preference.

Verify your new commit
# Show details about the latest commit:
git show
commit ec87f17c930b5c6f896ac04c9f8fd090d3d18853 (HEAD -> master)
Author: Nick Janetakis <nick.janetakis@gmail.com>
Date:   Sat Apr 16 10:59:28 2022 -0400

    Add files

diff --git a/a b/a
new file mode 100644
index 0000000..e69de29
diff --git a/b b/b
new file mode 100644
index 0000000..e69de29
diff --git a/c b/c
new file mode 100644
index 0000000..e69de29

That’s it, you can rm -rf /tmp/git-squash if you want to clean up the directory we made.

Here’s a video walk through of the above with a bit more context:

Demo Video

Timestamps

  • 0:07 – When you might want to do this
  • 0:25 – Going over the demo repo
  • 1:16 – How to pick the commit you want to squash into and then reset it
  • 2:26 – Creating our new commit message with all of changes we want staged
  • 3:10 – Showing our new commit’s details
  • 3:47 – This is mostly useful when working locally before you push your changes

How often do you make temporary local git commit messages? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per month (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments