git-rebase: A case study
by yaobin.wen
rebase is probably one of the most difficult operation in git because it requires a lot of carefulness and patience to do it right. Recently, I dealt with a complicated git rebase case so I wanted to write down my learning.
In this git rebase case, I needed to rebase a feature branch on top of the latest main branch origin/main. However, the latest main branch evolved in the following way:
- 1). At the beginning, there were two topic branches:
topic1andtopic2:topic1was based onmain.topic2was based ontopic1.
- 2). Later:
- More commits from other topic branches were merged into
main. - Meanwhile, a few commits were pushed into
topic1to fix bugs.
- More commits from other topic branches were merged into
- 3). Then, at some point:
topic1was rebased against the then-latestmainbranch in order to resolve the merge conflicts.- However,
topic2had never been rebased, so it still referred to some old commits that used to be ontopic1. See the commits in light green in the yellow box.
- 4). Eventually, the branch
topic1was merged intomain.
What I needed to do was rebase the branch topic2 against the latest branch main. The biggest challenge was handling the commits inside the yellow box: Those commits from the two branches were either identical or quite similar. Identical commits were easy to handle. In fact, git rebase will automatically skip them. The similar commits needed more attention, because we need to decide whether we need to keep them or skip them.
The commits outside the yellow box were much easier to handle: For the commits 3, 4, and 5, they were topic1-specific commits so they must be kept; for the commits 6 and 7, they were topic2-specific commits, so they must be kept too.
Now let’s think about what can cause the commits inside the yellow box to be similar but not identical.
The first case is that the branch main already has some changes that also appear in the topic branches. In the following illustration, the branch topic1 had the changes A=1 and B=2. However, the change A=1 was already merged into main. This may happen for two reasons:
A=1might be a more fundamental change that was required by multiple branches. Therefore, it may appear in not onlytopic1andtopic2, but also in a 3rd branch calledtopic3. Iftopic3was merged earlier thantopic1andtopic2, the changeA=1would be merged intomainbeforetopic1andtopic2were merged.A=1was only made intopic1, but it might be a bug fix that was urgent enough to be cherry-picked intomainbeforetopic1was merged.
As a result, when topic1 was rebased against main, the change A=1 was no longer needed because it was already done in main. The branch topic1 only needed to keep the change B=2, as illustrated below:
The second case is that the branch main introduced some condition that required the code in the branch topic1 be changed. For example, topic1 wanted to assign the value zero to A. However, a change in main used A as the divider in the expression C=B/A. See the following illustration:
As a result, A could no longer be zero. When topic1 was rebased against main, it must update A to be a non-zero value, such as 1. But the commit that was referred in the old topic1 commit still had the change A=0. See the following illustration:
In both cases, we need to keep the commits during rebase, so the conflicting changes can be kept for further resolution.
Tags: Tech - git