Git Rebase to Squash Commits to Most Recent Message

You’ve been working on a development branch over a couple days, testing things out and exploring solutions. You aren’t comfortable losing work, so you create superficial commits. They’re only for you so that you can recover prior work or failed experiments. Finally you arrive at a suitable solution and painstakingly create a commit with a message that will make you the talk of the town. Maybe the message includes benchmarks and well fleshed out reasoning for the chosen solution.

But something is wrong. The commits with superficial messages are still present. If you’re well prepared, you’ll be able to squash the commits together and copy and paste the golden message. However, sometimes that’s not possible.

So how do you squash several commits into one and take the most recent commit message?

Solution

  • Checkout a temporary branch that is based off your dev branch
  • Rebase it interactively against the desired base branch (typically main / master).
  • Mark the first commit to be edited
  • Mark the remaining commits to be fixed up
  • When editing the commit, commit with the message from the dev branch (can either use the commit’s SHA or the branch’s name)
  • You’re done and can rename this temporary branch as desired.

There is a stackoverflow thread that can be helpful as it contains some more information, but the solutions present are either sub-optimal for this scenario or not application. It is interesting to see how few people must have this question based on only a few upvotes. However, soon after devising this solution my co-worker asked me this exact question, so it must not be too rare.

Walkthrough

For a follow along example, we first set up the git history to exhibit the undesired situation.

git init
git commit --allow-empty -m "init"
git checkout -b dev
touch hello
git add -A
git commit -m "..."
touch world
git add -A
git commit -m "..."
touch foo
git add -A
git commit -m "the commit with good message"

Now we switch to our temporary branch

git checkout -b dev2
git rebase -i master

In the interactive screen, we’ll change the entries to edit the first one and fixup the rest:

edit b8847bc ...
fixup 8d20a62 ...
fixup 9e39d5b the commit with good message

Then we get dropped into the commit edit state and we will commit it with the good commit message with:

git commit --amend --reuse-message dev
git rebase --continue

With the rebase done we should be in the desired state except for the temporary branch name, which can be fixed with a rename:

git branch -M dev

Done!

I don’t normally post quick little tutorials but since I probably wasted a half hour looking for a better solution I figured I’d write this down for my future self.

Comments

If you'd like to leave a comment, please email hi@nickb.dev