Aaron M. Rice

Better than git rebase -i main

If you’re in the git situation where you want to rebase your working branch onto an updated main branch and you also want to squash commits on your working branch, you’d probably use git rebase -i main and do an interactive rebase. However, if you merely invoke git rebase -i main, git will rebase and then begin applying and squashing your commits, potentially forcing you to deal with conflicts that wouldn’t have come up while applying your squashed commits to the new base. In cases where there are conflicts, you’re better off squashing the commits before applying them to a new base, because you’ll have fewer & better conflicts (or at least no worse) to resolve when the commit is applied to a new base.

To squash your branch’s commits first, you want to git rebase -i onto your base’s original branch. The invocation git merge-base HEAD main will return the hash of the base commit shared by both main and your branch, the branch base before you rebase. To combine these in your shell, you’d type something like git rebase -i $(git merge-base HEAD main). This lets you squash your commits without changing the base first. Then you can follow up with a simple git rebase main to pull your squashed commits to the newest main branch.

To put it all together, what you probably want to use to squash and rebase:

git rebase -i $(git merge-base HEAD main) && git rebase main

or its slightly shorter equivalent:

git rebase -i $(git merge-base @ main) && git rebase main

I’ve put this in my ~/.gitconfig as:

[alias]
    squash = !git rebase -i $(git merge-base @ main)