How to rebase stacked Git branches
When working on a feature, you might split it into several stacked branches, so you can merge each one separately. But updating such branches can be annoying, since you have to manage each one. Git 2.38 (2022-10-15) makes such updates easier, with the ability to rebase a stack of branches at once, with the new
--update-refs. Let’s look at a couple of examples.
Imagine you have this situation, most recent commits first:
* e67fe90 Add deployment (main) | | * 73145a7 Add Poll views (HEAD -> poll_views) | | | * 3345a24 Add Poll database models (poll_models) |/ | * 86e3722 Set up Django
main branch has two commits on it. On the side, there are two stacked branches for a new “poll” feature,
Imagine you’d like to rebase the
poll_* branches on top of the latest
--update-refs, you’d need to first rebase
poll_models, then rebase
poll_views on top of the new
poll_models. But with the flag you can do this in one command.
First, switch to the final feature branch:
$ git switch poll_views
Second, rebase onto the
main branch with
$ git rebase --update-refs main Successfully rebased and updated refs/heads/poll_views. Updated the following refs with --update-refs: refs/heads/poll_models
Git tells about
poll_views being rebased, and that it update
poll_models in the process.
Now both branches live on top of the latest commit on
* c6ac1a3 Add Poll views (HEAD -> poll_views) | * 9f9622b Add Poll database models (poll_models) | * e67fe90 Add deployment (main) | * 86e3722 Set up Django
Imagine you had that same initial situation:
* bc63397 Add deployment (HEAD -> main) | | * 94d92fd Add Poll views (poll_views) | | | * 229c030 Add Poll database models (poll_models) |/ | * 86e3722 Set up Django
poll_views for code review, you have some changes to make to both. How can you make those changes, and ensure they end up in the right branches?
First, check out the last of the stacked branches:
$ git switch poll_views
Second, make changes applicable to both branches:
... $ git commit -m "Add database constraint to Poll model" ... $ git commit -m "Add rate-limiting to view" ...
Third, start an interactive rebase of the stack:
$ git rebase -i --update-refs main
-i is short for
--interactive, which enables rebase’s interactive mode. This will open your text editor with a file you can use to control rebase operations.
Fourth, change the rebase file to move the commits to the appropriate branches. When the file opens, you’ll see it starts like:
pick 229c030 Add Poll database models update-ref refs/heads/poll_models pick 94d92fd Add Poll views pick 31d5fc9 Add database constraint to Poll model pick af05cde Add rate-limiting to view # Rebase bc63397..af05cde onto bc63397 (5 commands) # # Commands: ...
pick lines list commits, in the order they’ll be rebased. The
update-ref line controls the commit that the
poll_models branch will point to after the rebase. These are also explained in the Commands comment from Git:
# p, pick <commit> = use commit ... # u, update-ref <ref> = track a placeholder for the <ref> to be updated # to this position in the new commits. The <ref> is # updated at the end of the rebase ...
In this case, the “Add database constraint to Poll model” commits should be part of
poll_models. Move its line above the
pick 229c030 Add Poll database models pick 31d5fc9 Add database constraint to Poll model update-ref refs/heads/poll_models pick 94d92fd Add Poll views pick af05cde Add rate-limiting to view # Rebase bc63397..af05cde onto bc63397 (5 commands) ...
Fourth, save and close the file, and Git will perform the instructed rebase:
$ git rebase -i --update-refs main Successfully rebased and updated refs/heads/poll_views. Updated the following refs with --update-refs: refs/heads/poll_models
Now the two branches are on top of the latest
main, with their respective commits:
* 9182779 Add rate-limiting to view (HEAD -> poll_views) | * df9ae26 Add Poll views | * d0cfd78 Add database constraint to Poll model (poll_models) | * e7ee0b7 Add Poll database models | * bc63397 Add deployment (main) | * 86e3722 Set up Django
Now you can send each branch for another round of code review, probably with
You can make it easier to use stacked branches by enabling
--update-refs by default. Then, every time you rebase a branch, any earlier branches in the stack will also get updated.
To enable the flag by default, for all repos, add the
rebase.updateRefs boolean option to your global config:
$ git config --global --add --bool rebase.updateRefs true
This will add the option in your
~/.gitconfig file like so:
[rebase] updateRefs = true
Make your development more pleasant with Boost Your Django DX.
One summary email a week, no spam, I pinky promise.
- How to Squash and Rebase a Git Branch
- How to Clean Up Unused Code With Git
- How to Run a Command on Many Files in Your Git Repository