Rebase Onto – When Dropping Commits Makes Sense: Git In Practice – Part 3

In the previous articles of this series, I showed you some of the capabilities of interactive rebase. I mentioned that you can also drop commits when rebasing. In this article, I would like to demonstrate scenarios in which that makes sense and a short-cut to achieve what we want.

In this article:

YB_300x300
Yannick Baron is architecture consultant at Thinktecture and focuses on Angular and RxJS.

Article series:

  1. Part 1: Demystifying git Rebase 
  2. Part 2: Interactive Rebase
  3. Part 3: Rebase Onto – When Dropping Commits Makes Sense

Associated Screencast: Rebase Onto: Git in Practice

Automatically Dropped Commits

Imagine the following graph:

				
					```
      A---B---C (feature)
     /
D---E---A---G (main)
```
				
			

As you can see, we have made change A on feature. Let’s say we added a line to a configuration file. We can also see main has moved further and also introduced the same change A.

If we now rebase feature onto main, commit A of feature would be empty and therefore will automatically be skipped for you, resulting in a graph as such:

				
					```
              B'--C' (feature)
             /
D---E---A---G (main)
```
				
			

When rebasing, changes that are already in the base might result in empty commits, which git skips.

Branching off a Feature

Sometimes, when developing a feature, you are reliant on a recently developed addition to your codebase. Assume that the changes you need are in a feature branch that has not been integrated into main yet.

What you can do in this case is to base your branch off of the feature branch you are waiting on:

				
					```
                        X---Y---Z (feature)
                       /
              A---B---C (feature-base)
             /
D---E---F---G---H---I (main)
```
				
			

But what do we see here? main has moved ahead of feature-base. It is not unusual for the person in charge of feature-base to now rebase onto main, to integrate the changes, and ready the feature for a merge:

				
					```
                A---B---C---X---Y---Z (feature)
               /
              /       A'--B'--C' (feature-base)
             /       /
D---E---F---G---H---I (main)
```
				
			

feature-base is now based on main, and commits A through C have been re-applied.

If the rebase of feature-based went smoothly without any conflicts, and we rebase feature onto it, we will not run into problems, and git skips the empty commits as explained above.

That is not always the case. Also, imagine feature-base also moved a little further and was integrated into main already. Either way, our goal would be to only take the commits of our feature branch, in this case, X, Y, and Z, to a new base.

When using interactive rebase, to rebase feature onto feature-base, we see something like this:

				
					pick 9a56133 A
pick bf1de76 B
pick 5bc89ff C
pick bebdada X
pick 4ab9db0 Y
pick 47ff725 Z
				
			

We now have the option to drop commits A, B, and C, by either removing the lines in the editor or changing the command to drop, resulting in applying commits X through Z to where we need them to be.

				
					```
                                X'--Y'--Z' (feature)
                               /
                      A'--B'--C' (feature-base)
                     /
D---E---F---G---H---I (main)
```
				
			

Using an interactive rebase, dropping some commits is quite simple, even when they are in the middle of a series. If we want to omit some commits at the beginning only, there is a shorter form built into the rebase command.

Rebase --onto

Let’s assume to be in the same situation as before:

				
					```
                        X---Y---Z (feature)
                       /
              A---B---C (feature-base)
             /
D---E---F---G---H---I (main)
```
				
			

Imagine that this time, we simply want to transplant X, Y, and Z, onto main. Using the rebase command, we can achieve this by doing the following:

				
					$ git rebase --onto <base> <upstream> [<branch>]

$ git rebase --onto main feature-base feature
				
			

Executing the command will get us this graph:

				
					```
                A---B---C (feature-base)
               /
              /       X'--Y'--Z' (feature)
             /       /
D---E---F---G---H---I (main)
```
				
			

As you can see in the onto-form of the rebase command, we need to provide the upstream from which we want to pluck the commits.

In the above example, we still have a reference to that in the form of the feature-base branch. Let’s look back at the situation we encountered before:

				
					```
                A---B---C---X---Y---Z (feature)
               /
              /       A'--B'--C' (feature-base)
             /       /
D---E---F---G---H---I (main)
```
				
			

Here, we do not have that reference.

But fear not! Instead of the upstream reference, we can just use the SHA hash of commit C. Assuming that feature is the current branch, the shortest form would be:

				
					$ git rebase --onto feature-base 5bc89ff
				
			

Now we replicated our interactive rebase from before, resulting in:

				
					```
                                X'--Y'--Z' (feature)
                               /
                      A'--B'--C' (feature-base)
                     /
D---E---F---G---H---I (main)
```
				
			

Conclusion

In this article, we looked at dropping commits when rebasing and introduced the --onto flag, the rebase command provides. I am using this way of rebasing frequently, so I wanted to demonstrate it here and hope that you can benefit from it as much as I do.

Free
Newsletter

Current articles, screencasts and interviews by our experts

Don’t miss any content on Angular, .NET Core, Blazor, Azure, and Kubernetes and sign up for our free monthly dev newsletter.

EN Newsletter Anmeldung (#7)
Related Articles
.NET
pg
Domain models often involve concepts that exist in multiple distinct states or variations. Traditional approaches using enums and nullable properties can lead to invalid states and scattered logic. This article explores how discriminated unions provide a structured, type-safe way to model domain variants in .NET, aligning perfectly with Domain-Driven Design principles while enforcing invariants at the type level.
06.10.2025
.NET
pg
Learn how to seamlessly integrate Smart Enums with essential .NET frameworks and libraries. This article covers practical solutions for JSON serialization, ASP.NET Core model binding for both Minimal APIs and MVC controllers, and Entity Framework Core persistence using value converters. Discover how Thinktecture.Runtime.Extensions provides dedicated packages to eliminate integration friction and maintain type safety across your application stack.
21.09.2025
.NET
pg
Value objects are fundamental building blocks in Domain-Driven Design, serving far more than simple data wrappers. This article explores their strategic importance in bridging technical code and business concepts, enforcing domain rules, and fostering clearer communication with domain experts. Learn how to build robust aggregates, cultivate ubiquitous language, and encapsulate domain-specific behavior using Thinktecture.Runtime.Extensions in .NET applications.
16.09.2025