Git: Squash and rebase a branch with --keep-base

We gotta Git out of this place.

Update (2023-10-16): This post’s content appears in my new book Boost Your Git DX.

When you have a long-lived feature branch with many “work in progress“ commits, it can become tiresome to rebase it onto your main branch due to conflicts. You can end up fixing conflicts in the same areas of the same files over and over for multiple commits.

Before rebasing such branches, you may want to squash some or all commits together, and then rebase that single commit onto the main branch, handling conflicts once. Here’s how to do that.

Imagine you’ve been working on the feature branch polyrhythms, and you want to squash and rebase it onto main:

$ git log --oneline --graph polyrhythms main
* d05bb2e (HEAD -> polyrhythms) Tweak polyrhythms again
* 60f90ca Tweak polyrhythms
* dab2b47 Add experimental polyrhythms
| * bd3c9c6 (main) Phat bass
|/
* e1220b1 Hi-hat vibes

First, ensure you are on the feature branch:

$ git switch polyrhythms

Second, use an interactive rebase to squash the branch on top of its original base commit:

$ git rebase -i --keep-base main

--keep-base flag tells Git to rebase on to the base commit from main that the branch was created from. Unlike the default behaviour of using the latest commit of the target branch, this will not pull in newer commits from main. Thus, there won’t be any conflicts.

Third, change the rebase file to squash all commits into the first one with f (fixup):

p dab2b47 Add experimental polyrhythms
f 60f90ca Tweak polyrhythms
f d05bb2e Tweak polyrhythms again

# Rebase e1220b1..d05bb2e onto e1220b1 (3 commands)
#
# Commands:
...

You could also use the s (squash) action to edit the combined commit message. But generally, I find f (fixup) is more useful because my WIP commits tend not to say anything of value (“updates”, “edit X”, etc.).

Fourth, save and close the file, and Git will perform the rebase, squashing all commits into one:

$ git rebase -i --keep-base main
Successfully rebased and updated refs/heads/polyrhythms.

After this completes, you can look at the log to see your single commit:

$ git log --oneline
8ace6b5 (HEAD -> polyrhythms) Add experimental polyrhythms
e1220b1 Hi-hat vibes
...

Fifth, you can now rebase your single commit onto your main branch. You may want to first pull the latest version of your main branch:

$ git switch main
Switched to branch 'main'

$ git pull
...

$ git switch -
Switched to branch 'polyrhythms'

Then, rebase your feature branch:

$ git rebase -i main

(It’s not really necessary to use -i for interactive mode here, since you don’t need to make any changes. But I encourage you to make a habit of using interactive mode, to double-check what you’re rebasing.)

As Git applies the rebase, you might have to deal with conflicts, and complete the commit git rebase --continue. This is easier than before squashing though, as now all the branch changes are in a single commit.

Fin

All your rebase are belong to us,

—Adam


Read my book Boost Your Git DX for many more Git lessons.


Subscribe via RSS, Twitter, Mastodon, or email:

One summary email a week, no spam, I pinky promise.

Related posts:

Tags: