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
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
Angular
SL-rund
If you previously wanted to integrate view transitions into your Angular application, this was only possible in a very cumbersome way that needed a lot of detailed knowledge about Angular internals. Now, Angular 17 introduced a feature to integrate the View Transition API with the router. In this two-part series, we will look at how to leverage the feature for route transitions and how we could use it for single-page animations.
15.04.2024
.NET
KP-round
.NET 8 brings Native AOT to ASP.NET Core, but many frameworks and libraries rely on unbound reflection internally and thus cannot support this scenario yet. This is true for ORMs, too: EF Core and Dapper will only bring full support for Native AOT in later releases. In this post, we will implement a database access layer with Sessions using the Humble Object pattern to get a similar developer experience. We will use Npgsql as a plain ADO.NET provider targeting PostgreSQL.
15.11.2023
.NET
KP-round
Originally introduced in .NET 7, Native AOT can be used with ASP.NET Core in the upcoming .NET 8 release. In this post, we look at the benefits and drawbacks from a general perspective and perform measurements to quantify the improvements on different platforms.
02.11.2023