When I don't rebase

I always rebase my feature branches, rather than merging them. Except when I don't.

Yesterday I made the case for my two simple rules about git merge vs rebase:

  1. Merge into main.
  2. Otherwise rebase.

And I promised to talk about some exceptions to those two simple rules. Here I go…

  • A feature branch has multiple contributors — Rebasing rewrites git history, by changing (at least) the git SHAs of each commit. If your feature branch has been checked out by more than one person, and you rebase, it becomes impossible for those other contributors to git pull updates to that branch. What’s worse, if they have unpushed changes, now they’re in a real pickle! So: If you have multiple contributors on a feature branch, merge instead of rebase.

    However: Never have multiple people working on a feature branch! Merge to main more frequently instead!

  • You have a really big, ugly, hairy, nasty, icky, confusing feature branch. — Somehow you’ve painted yourself into corner. You have 3 months worth of work in a feature branch. You’ve been merging from main into your feature branch every day or two as you make progress on your new killer feature. Then you read my advice to stop merging, and somehow I convinced you. So you try rebasing that monster branch and… !@#$%^&*

    In this case, you’re forgiven to merge main into your feature branch. Rebasing at this stage is going to require a lot of nasty conflict resolution for code that changed days, weeks, or even months ago. That’s a dangerous conflict to resolve, because you’ve forgotten the context. So you’re best taking the hit and merging. This time.

    However: Never have long-lived feature branches! Merge into main more frequently instead!

  • You have a branch with a lot of back-and-forth in PR comments — In this case, rebasing can make code review more difficult, as inline comments/discussions tend to lose their place, and GitHub will detect changes on each file, even those not changed, forcing reviewers to re-review files. Using merge in this case works more naturally with the code review tools, and makes it easier to see which changes have been made since the last review.

    However: Never have long back-and-forth discussion on PRs! Merge into main more frequently instead!

  • Your PR merge policy requires that your branch is up to date — That is to say, if the main branch has been updated since your PR branched from it, and merging policy requires you update your branch (a very reasonable policy), then hitting the “Update Branch” button in GitHub will typically do a merge from main into your feature branch. While this does leave an ugly scar commit (which I talked about yesterday), I believe this is the lesser of the available evil options.

Alternatives include:

  • Manually rebasing locally, then pushing your changes up again. I often do this, but when the PR is already approved, this may invalidate existing approvals, depending on configuration, which would further delay interation. In these cases, I’ll just hit that “Update Branch” button, usually followed by the “Auto-Merge” button, to merge the changes as soon as the checks pass.

  • Rebasing rather than merging in GitHub. I’m not actually sure if GitHub allows this. GitLab does. But this is annoying if you ever need to add a commit to the PR, since now your local branch is different than the remote one (this is the same as the problem with multiple contributors described above).

  • Squash-merge everything. Ugh. You already know why I hate this.

    However: Never… Actually. I think this is a mostly reasonable use of merging, given the limitations of GitHub. At least these merge commits are always empty (that is–there’s no conflict resolution included.)

There may be other exceptions to my 2 simple rules that I’ve run into. They’re rare enough I can’t remember them.

And even these two exceptions are very rare. I typically run into them when first joining a team that’s still not accustomed to small PRs. These exceptions should be exceptional. And they should be temporary fixes, on the way to smaller PRs and continuous integration.

Did I miss an exception you think deserves a call-out?

Share this