Git: Rebase an old branch incrementally

Zig-zag rebases

You worked on a sizeable feature branch some time ago but left it to focus on other things. Now you’re ready to pick it up, so you want to rebase it onto your updated main branch. But when you try that, you’re presented with an overwhelming number of merge conflicts.

Nothing can make all those conflicts go away. But if you incrementally rebase the feature branch, you can handle them in manageable chunks.

Before you begin, consider squashing all commits on your feature branch into one. Doing so will reduce the number of times you’ll need to resolve conflicts, and it’s especially worthwhile if you squash-merge branches anyway. To do so, follow steps 1-4 of my previous post, Git: How to squash and rebase a branch.

To incrementally rebase your branch, follow these steps.

First, save a log of commits on the main branch since your feature branch split from it. From the feature branch run:

$ git log --reverse --oneline ..main > log

Note:

Open up log to see the list of commit SHAs and titles:

068e7b5 Catch weedle
d5d3696 Catch caterpie
916ac35 Evolve weedle into kakuna
...
d2179f2 Catch venonat

Second, repeatedly rebase onto commits from the log file, top to bottom. Once you rebase onto the final commit, your feature branch is up to date.

Use this invocation:

$ git rebase <SHA>

Replace <SHA> with a commit SHA selected from the log file.

Pick target commit SHAs depending on the number to work through and the chance of merge conflicts. If there are only a few commits, it may make sense to target them individually. But if there are many, step through them in batches.

Pick batches intelligently if you can or in manageable chunks if not. For example, if you know which commits have conflicting changes, you might step through them individually whilst skipping over the others. Otherwise, you might try batches of 20% at a time for five rebases total.

If a rebase has too many merge conflicts, you can always stop it with git rebase --abort. Then, try again with a smaller batch or a single commit.

Here’s an example session with five rebases, two of which encounter merge conflicts:

$ git rebase d5d3696
Auto-merging pokemon.txt
CONFLICT (content): Merge conflict in pokemon.txt
...

$ edit pokemon.txt

$ git add pokemon.txt

$ git rebase --continue
[detached HEAD b681bab] Level up wartortle
 1 file changed, 6 insertions(+)
Successfully rebased and updated refs/heads/grindfest.

$ git rebase cdc2ca0
Successfully rebased and updated refs/heads/grindfest.

$ git rebase 14aa7ab
Successfully rebased and updated refs/heads/grindfest.

$ git rebase 1eb4875
Auto-merging pokemon.txt
CONFLICT (content): Merge conflict in pokemon.txt
...

$ edit pokemon.txt

$ git add pokemon.txt

$ git rebase --continue
[detached HEAD 7b2f864] Level up wartortle
 1 file changed, 6 insertions(+)
Successfully rebased and updated refs/heads/grindfest.

$ git rebase d2179f2
Successfully rebased and updated refs/heads/grindfest.

Fourth, remove the temporary log file:

$ rm log

Then you’re all done!

Fin

May your merge conflicts be easily resolved,

—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: