Rebase --onto

Here we consider the --onto flag of git-rebase – it gives fine-grained control over the rebase process by allowing to move a range of commits onto a new base commit. There are two examples: the first one simply illustrates the syntax, while the second one describes a scenario where using the --onto flag is particularly well-suited.

The basic format of the command is:

git rebase --onto <new-base> <range-start> <range-end>

The range of commits to rebase onto the <new-base> is formed using <range-start>..<range-end> (the former is excluded from the range, while the latter is included).

Example 1

We consider four cases. In all of them, the “Before” tab depicts the same repository with two branches (main and feature) – the only difference being the highlighted range of commits, which is precisely the range used in the rebase command (included at the top on the “After” tab).

In the first case we consider a vanilla rebase command git rebase main feature, which is equivalent to git rebase --onto main main feature, i.e., the changes of the commits in the range main..feature are applied starting from the tip of main. As can be seen in the “After” tab, commits C, D and E have been recreated (compare their tooltips), that is:

  • C: f8ed6cdbd093d7

  • D: 30168f08bb9c6c

  • E: 7d655dcd56f7af.

Of course, the original three commits are still available in the repository, however, they are unreachable from any branch (or tag) and, normally, would be garbage-collected eventually (note that they are displayed with a different color [1]).

Visualize DAG
git dag -l -H -u -R main..feature
git rebase main feature
Visualize DAG
git dag -l -H -u

The range in the second case, is the same as in the first case even though it is defined using b5c0976..feature (b5c0976 is the merge-base of main and feature). The difference here is that we rebase not on the tip of main but on main~1 (i.e., commit 1202fea).

Visualize DAG
git dag -l -H -u -R b5c0976..feature
git rebase --onto main~1 b5c0976 feature
Visualize DAG
git dag -l -H -u

In case 3 we rebase again on top of main~1 but this time the range has one commit less (we dropped commit C).

Visualize DAG
git dag -l -H -u -R f8ed6cd..feature
git rebase --onto main~1 f8ed6cd feature
Visualize DAG
git dag -l -H -u

Finally, in case 4, we use the last commit on the feature branch (instead of the feature branch itself) to define the range. After the rebase, the HEAD is detached [2] (i.e., the feature branch didn’t move). This could be considered as a useful trick – we perform the rebase, then move feature to point to HEAD (i.e., to the updated E commit ce51afe) if we are happy with the results (see the last two tabs) [3].

Visualize DAG
git dag -l -H -u -R f8ed6cd..feature~0
git rebase --onto main~1 f8ed6cd feature~0
Visualize DAG
git dag -l -H -u
git branch -f feature HEAD
# alternative: git update-ref -m "reflog MSG" refs/heads/feature HEAD
Visualize DAG
git dag -l -H -u
git switch feature
Visualize DAG
git dag -l -H -u

Example 2

In the second example we reuse the repository from section “More Interesting Rebases” in Git Branching - Rebasing, however we perform a different sequence of operations.

Suppose that, to add some server-side functionality, Elena commits 103ff1e (C3) on a feature branch server. A bit later Marina, adds related client-side functionality on a client branch. Then both of them continue working on their implementations. Meanwhile, main has evolved and Elena decides to rebase server on it (lets assume that she resolved a conflict in the C3 commit). The result is depicted in the second tab below.

At that point Marina wants to sync her client branch with the updated server branch, but she doesn’t want to resolve the same conflict with C3 (after all, it has already been resolved by Elena). So she uses the --onto flag of git rebase as shown in the third tab below. Note that the range 103ff1e..client doesn’t include 103ff1e – in effect, she only rebases her own work (commits C8 and C9).

Visualize DAG
git dag -l -H -u
git rebase main  # note that we are on the server branch
Visualize DAG
git dag -l -H -u
git rebase --onto server 103ff1e client
Visualize DAG
git dag -l -H -u