The letter A styled as Alchemists logo. lchemists
Published July 14, 2024 Updated July 15, 2024
Cover
Git Rebase AutoSquash

Git Rebase is my only workflow because it leads to clean Git histories, automatic release notes, improved team/stakeholder communication, leveling up of new team members, and so much more. This is especially true when coupled with Git Lint and Milestoner.

One of many tricks, when rebasing, is to reduce as much manual labor as possible. This article will teach you how to configure Git to use AutoSquash so you can do less work especially when it comes to automatically moving and resolving your fixup!, amend!, and squash! Git directives to the correct location when rebasing. ⚡️

Table of Contents

Quick Start

To quickly configure Git with AutoSquash enabled, run the following in your terminal:

git config --global rebase.autoSquash true

That’s it! To learn more about this simple change, read on.

Tutorial

To set the stage, we’ll start with a new Git repository by using Rubysmith to build a new Ruby project for us:

rubysmith build --name tutorial
cd tutorial
git config --add rebase.autoSquash false
git switch --create calculator --track

We’ll use this project to build a simple Ruby calculator. The code won’t be interesting but how we resolve our Git commits will be. Now we can add our initial implementation:

printf "%s\n\n" "# frozen_string_literal: true" > bin/calc.rb
printf "%s\n" 'ARGV.then { |a, b| puts "#{a} plus #{b} is #{a + b}." }' >> bin/calc.rb
git add bin/calc.rb
git commit --all \
           --message "Added initial implementation" \
           --message "Necessary to perform addition calculations."
printf "%s\n" "Usage: ruby calc.rb <first number> <second number>" > README.adoc
git add README.adoc
git commit --all \
           --message "Added implementation documentation" \
           --message "Necessary to document usage."

Before we start, let’s look at our Git history from our calculator branch:

git log

# 60e7505ac62f G Brooke Kuhlmann Added implementation documentation (HEAD -> calculator) 13 seconds ago.
# acc8dc688e72 G Brooke Kuhlmann Added initial implementation 31 seconds ago.
# f9379657bcce G Brooke Kuhlmann Added project skeleton (main) 2 minutes ago.

Great, now let’s see how our implementation works:

ruby bin/calc.rb 1 2
# 1 plus 2 is 12.

The above is definitely a bug so let’s fix by editing our implementation to use a.to_i and b.to_i so that the implementation now looks like this:

ARGV.then { |a, b| puts "#{a} plus #{b} is #{a.to_i + b.to_i}." }

After saving the above changes and running the script again, we’ll see the following:

ruby bin/calc.rb 1 2
# 1 plus 2 is 3.

Much better as you can see the arithmetic is correct. Let’s fixup our changes by using the SHA of our original commit message (i.e. "Added initial implementation") as shown in our Git history from earlier (keep in mind that your SHA will be different than mine):

git add bin/calc.rb
git commit --fixup acc8dc688e72

With our fixup commit in hand, we can now rebase:

git rebase --interactive

Notice that you see the following in your Git rebase editor (💡 I’m using Git Rebase Abbreviations in case you’re curious):

p acc8dc688e72 Added initial implementation
p 60e7505ac62f Added implementation documentation
p 3685d72f4aed fixup! Added initial implementation

There are two problems with this situation:

  1. Our fixup! commit is at the bottom of the list and needs to be moved next to acc8dc688e72.

  2. Our fixup! commit is using p for pick instead of f for fixup.

We can manually fix this by moving our fixup! commit next to the acc8dc688e72 commit, changing p to f, saving, and exiting our editor but let’s avoid manual labor by teaching Git to do this automatically!

First — while still in your Git rebase editor — delete everything, save, and then exit to abort the rebase. Now, let’s teach Git to AutoSquash by configuring Git as follows:

git config --add rebase.autoSquash true

With AutoSquash enabled, we can rebase once more:

git rebase --interactive

You’ll now see the following in your editor:

p acc8dc688e72 Added initial implementation
f 3685d72f4aed fixup! Added initial implementation
p 60e7505ac62f Added implementation documentation

Notice the change in the above versus what happened before:

  1. Our fixup! commit has been moved next to the original commit (i.e. acc8dc688e72) that needs fixing.

  2. The fixup! commit was renamed from a p (pick) to a f (fixup).

Much better! The best part is AutoSquash works for all Git directives: fixup!, amend!, and squash!. This is a huge time saver when rebasing since Git can figure all of this out and do the work for you.

To wrap up, let’s look at our Git log one last time:

git log

# 39824206be7f G Brooke Kuhlmann Added implementation documentation (HEAD -> calculator) 3 seconds ago.
# b7d588bacaa8 G Brooke Kuhlmann Added initial implementation 3 seconds ago.
# f9379657bcce G Brooke Kuhlmann Added project skeleton (main) 8 minutes ago.

Notice that our fixup! commit is gone and properly applied to b7d588bacaa8. You’ll also notice the SHAs, on our calculator feature branch, changed due to the rebase but that is expected when rebasing because we’re changing the original commits on our feature branch.

Now that you know how to AutoSquash, I’d strongly recommend adding this to your global configuration so all projects benefit from this behavior by running the following:

git config --global --add rebase.autoSquash true

Conclusion

This is one of those easy configuration changes — and one I’ve used for many years — that speeds up your workflow considerably. Enjoy!