Matthieu Vergne's Homepage

Last update: 07/01/2022 18:22:19

How to Rebase a Git Branch Iteratively?

Context

While we work on our own branch, other changes might be merged in the main branch. At some point, we might want to rebase our work on them, at least before to merge. If our branch lives a long time, it is better to do it on a regular basis to avoid having to rebase on a lot of changes at once. However, it sometimes happens that we have to rebase an old branch on many commits, like a forgotten branch that we want to update.

Question

The main issue is the heavy effort required to integrate a lot of changes at once. Instead, we would like to integrate a small piece of it, one at a time. It would allow to go one easy step after another, and stop at some point to continue later. In other words : how to rebase a Git branch iteratively?

Method

Before to go, identify the branch or commit to rebase on:


BASE=<branch or commit>

If it is a remote branch, don't forget to get its last commits with git fetch (not git pull, which is a fetch+merge).

It is possible to rebase your branch on this base one step at a time, in a controled way. To do so, instead of rebasing all at once, we can rebase one commit (or some of them) at a time. We can repeat the operation until we reach the most recent commit. There is, however, two ways to understand an "iterative" rebase:

  1. iterate your own branch: rebase one commit of your branch on the most recent commit of the base branch
  2. iterate the base branch: rebase all your branch on the immediately next commit of the base branch

The point 1 is not what we will focus on in this article. Indeed, this is the usual way to go and how Git works, so there is plenty of support for that elsewhere if you are interested. By using a classical rebase, Git helps you to redo each of your commits on the base branch. However, you will remain stuck in the rebase process until all your branch is rebased. Instead, you can create a temporary branch on the base and cherry-pick your commits one at a time. It allows you to stop and continue later if needed, but you will have to deal with the new commits added to the base branch, enforcing you to redo it. In any case, you rebase on a lot of commits at once, meaning you have to integrate a lot of changes in your branch in a single pass.

Here, we deal with point 2. The difference is that we assume that you master the content of your own branch, but discover progressively the new commits of the base branch. You can clean your branch to reduce the conlicts resolution efforts, but then you go for rebasing all of it on a single (or few) new commit(s). If new commits are added to the base branch during the process, it changes nothing to the procedure, just executing more iterations of it. Here is the procedure to repeat until the rebase is complete:

Step Goal Command
1 Display the remaining commits to rebase on
git log --oneline HEAD..${BASE}
2 Identify the target commit to rebase on

				COMMIT=$(git log --pretty=format:"%h" HEAD..${BASE} | tail -1) # Retrieves the next commit of the base branch
				git log --oneline ${COMMIT} | head -1                          # Confirm the target commit
			

We can use a more recent commit from the list provided in the previous step to rebase on several commits at once. The critical point is to target a commit that passes all the tests.

3 Analyse the changes brought by the target commit to estimate the potential conflicts and other required actions
git diff $(git merge-base HEAD ${BASE}) ${COMMIT}
4 Rebase your branch on the target commit and resolve potential conflicts
git rebase ${COMMIT}
5 Update submodules if you use them
git submodule update
6 Validate the rebase
mvn clean test # If you use Maven

Adapt this step to your context. If you have automated or manual tests that can be executed, do it. If other tests are adapted to a more recent state and are expected to fail for now, ignore them. If you are on the last iteration and the rebase is complete, all the tests should be executed.

Answer

You can iteratively rebase your own branch on another by using a classical rebase or cherry-pick. However, it means rebasing on all the base commits at once. You may prefer instead to rebase on the few next commits of the base branch first, and repeat until your reach the last one. It allows you to look at these new commits one at a time to integrate them in your branch more easily. To reduce the conflicts resolution effort, you may also clean your branch before to rebase anything.

Bibliography