Peepcode-git.pdf: Best strategy to keep a long standing feature branch in sync with main branch with rebase

In the following documentation peepcode-git.pdf located at https://github.com/pluralsight/git-internals-pdf/releases, page 39 notes different use cases for rebase. Particularly this quote:

"If you get a huge project or idea – say refactoring the entire code base to the newest version of your framework or switching database vendors or something, you create a long-term branch, continuously rebase it to keep it in line with other development, and once every - thing is tested and ready, merge it in with your master."

The thing is the examples in the e-book goes over the ideas, the abstract applications for rebase but it doesn't provide concrete commands the user can reproduce examples against it. I can follow most of it except the "continuous rebase" part. Typically, when I have rebased I found it effective when:

  • I am working on a branch of which I don't know how many commits I will make to get to the solution. Usually when I am experimenting with some code and it doesn't work, I put a note in the commit log to squash that commit since it offers no value. When I finally figure out the desired content state of my code, I rebase the branch to just the important commits, squashing out the others as stated. I then replay those changes via rebase onto the main branch.

If I am working on a long task however, I don't quite understand the idea of rebasing main onto my branch to stay in sync with it as it means that each commit in main will be replayed into a new commit onto my feature branch but it would the exact same content state. This seems counter intuitive as valuable information is lost when the commit hash changes. Additionally, when it comes time to put feature branch work onto main, it would replay all its changes onto main including the duplicate commits (with different hashes) onto main. I think it would make more sense to continually merge main onto your local branch to keep it in sync with main and then when complete, rebase it onto main. This would help keep the merge-base to a newer point and reduce the number of commits that are replayed onto main. What am I missing?


Solution 1:

This is a simple misunderstanding. The suggestion is not what you assumed:

If I am working on a long task however, I don't quite understand the idea of rebasing main onto my branch to stay in sync...

Instead, you would regularly rebase your branch onto main. For example:

git switch my-long-lived-branch
git fetch
git rebase origin/main

Note it's possible that you could have conflicts when doing this type of rebase, if someone changed the same files on main that you changed on your branch.

You also mentioned:

When I finally figure out the desired content state of my code, I rebase the branch to just the important commits, squashing out the others as stated.

That is another kind of rebase; an interactive rebase with the intent of fixing up your in-progress commits. You can do this separately against the merge-base (starting commit of your branch) anytime without having conflicts:

# if you know the commit ID of the parent of your first commit:
git rebase -i parent-ID-of-your-first-commit
# or if you have many commits and don't want to bother looking it up
git rebase -i $(git merge-base HEAD origin/main)

As for your suggestion about merging instead of rebasing:

I think it would make more sense to continually merge main onto your local branch to keep it in sync with main and then when complete, rebase it onto main.

That would work fine, and so would the branch rebase, for bringing your branch up to date with the latest origin/main. I think it comes done personal preference. I personally prefer rebasing over merge in this situation, and if you're interactive rebasing anyway, you might as well do the branch rebase regularly as well.