<commit_before>---
layout: post
title: Git rebase --onto
---

<!-- markdownlint-disable MD033 -->

I generally prefer to keep my git history as a straight line. And my branches (when I have to use them) based on the HEAD of main. I pull main and rebase my branch onto it fairly often to keep up to date with the latest changes.

Recently I’ve been in the unfortunate position where it made sense to use a branch off a branch. This can be a pain to keep up to date with the latest changes on main.

<figure>
  <img src="/public/assets/branch-off-branch.excalidraw.png" alt="A branch off a branch"/>
  <figcaption>Branching off an existing branch</figcaption>
</figure>

Fortunately, a colleague introduced me to `git rebase --onto` which (while still a faff) made this process much easier.

The [git rebase docs](https://git-scm.com/docs/git-rebase) specify this form:

```bash
git rebase --onto <newbase> [<upstream> [<branch>]]
```

Though I like to think of it like this:

```bash
git rebase --onto <ONTO>
                  <FROM> # Exclusive
                  <TO>   # Inclusive
```

The example given shows how to rebase a **topic** branch onto **main**, where **topic** is currently based on **next**: `git rebase --onto master next topic`. Here you are rebasing onto **main**, from **next** up to **topic**.

*\<branch\>* (or *\<TO\>*) defaults to HEAD. In other words, if you’re already on the branch you want to work with, you can omit it. In the above example, if you have checked out **topic** then you can run: `git rebase --onto master next`.

What we want to do is slightly different. Let's have a look.

We start with our two branches, and a new commit on main which we’ve recently pulled, and then rebase the first branch onto main. This leaves an old commit behind, which our second branch is still based on. We then want to rebase our second branch onto the first.

In many cases `git rebase B1 B2` will work, which makes this tempting. However, if there was a merge conflict when rebasing B1 onto main, then the text diffs between the Old and New commits might differ. In which case, you’ll end up with some unwanted commits on your new B2 branch. If you had a lot of commits on B1, this could get very messy!

<figure>
  <img src="/public/assets/git-rebase-onto.excalidraw.png" alt="git rebase --onto"/>
  <figcaption>Using <code>git rebase --onto</code></figcaption>
</figure>

(You might want to open the image in a new tab to see it full size.)

So there we have it. Mainly I’m just writing this as a reminder for myself if I have to do this again (let’s hope not).

This is just one use for `git rebase --onto`. See the links below for more information about what else you can do with it.

## Further reading

- [`git-rebase` docs](https://git-scm.com/docs/git-rebase)
- [Git rebase --onto an overview](https://womanonrails.com/git-rebase-onto)<commit_msg>Make branch references more consistent<commit_after>---
layout: post
title: Git rebase --onto
---

<!-- markdownlint-disable MD033 -->

I generally prefer to keep my git history as a straight line. And my branches (when I have to use them) based on the HEAD of **main**. I pull **main** and rebase my branch onto it fairly often to keep up to date with the latest changes.

Recently I’ve been in the unfortunate position where it made sense to use a branch off a branch. This can be a pain to keep up to date with the latest changes on **main**.

<figure>
  <img src="/public/assets/branch-off-branch.excalidraw.png" alt="A branch off a branch"/>
  <figcaption>Branching off an existing branch</figcaption>
</figure>

Fortunately, a colleague introduced me to `git rebase --onto` which (while still a faff) made this process much easier.

The [git rebase documentation](https://git-scm.com/docs/git-rebase) specifies this form:

```bash
git rebase --onto <newbase> [<upstream> [<branch>]]
```

Though I like to think of it like this:

```bash
git rebase --onto <ONTO>
                  <FROM> # Exclusive
                  <TO>   # Inclusive
```

The example given in the git documentation shows how to rebase a **topic** branch onto **master**, where **topic** is currently based on **next**: `git rebase --onto master next topic`. Here you are rebasing onto **master**, from **next** up to **topic**.

*\<branch\>* (or *\<TO\>*) defaults to HEAD. In other words, if you’re already on the branch you want to work with, you can omit it. In the above example, if you have checked out **topic** then you can run: `git rebase --onto master next`.

What we want to do is slightly different. Let's have a look.

We start with our two branches, and a new commit on **main** which we’ve recently pulled, and then rebase the first branch onto **main**. This leaves an old commit behind, which our second branch is still based on. We then want to rebase our second branch onto the first.

In many cases `git rebase B1 B2` will work, which makes this tempting. However, if there was a merge conflict when rebasing **B1** onto **main**, then the text diffs between the *Old* and *New* commits might differ. In which case, you’ll end up with some unwanted commits on your new **B2** branch. If you had a lot of commits on **B1**, this could get very messy!

<figure>
  <img src="/public/assets/git-rebase-onto.excalidraw.png" alt="git rebase --onto"/>
  <figcaption>Using <code>git rebase --onto</code></figcaption>
</figure>

(You might want to open the image in a new tab to see it full size.)

So there we have it. Mainly I’m just writing this as a reminder for myself if I have to do this again (let’s hope not).

This is just one use for `git rebase --onto`. See the links below for more information about what else you can do with it.

## Further reading

- [`git-rebase` docs](https://git-scm.com/docs/git-rebase)
- [Git rebase --onto an overview](https://womanonrails.com/git-rebase-onto)
{'fraction_non_alphanumeric': 0.10301893228722497, 'fraction_numerical': 0.0027289783387344363, 'mean_word_length': 3.6650755767700876, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '956719', 'n_tokens_mistral': 1718, 'n_tokens_neox': 1648, 'n_words': 899}