DEV Community

Cover image for A closer look at git rebase
Jason McCreary
Jason McCreary

Posted on • Originally published at jason.pureconcepts.net

A closer look at git rebase

Most of the comments to my recent articles on 3 Git commands I use every day and When to make a Git commit have mentioned using git rebase.

So, let's talk about git rebase. Jumping right in, I use git rebase for two reasons:

  1. To bring a stale branch up to date.
  2. To change a set of unmerged commits.

Let's take a closer look at both of these.

Bringing a branch up to date

For some, git rebase falls on the magic end of the spectrum for Git commands. Yet, if we break down the actions taken by git rebase we can understand the magic.

While a tree is the goto analogy when visualizing Git commands, I find video editing also helps describe git rebase.

In the case of bringing a stale branch up to date, let's consider the following tree progression.

Visual of commit tree during git rebase

Starting with the full tree, we have a stale branch (in red) off a master branch. If we zoom in, we see the branch is stale because it's missing the recent commits from master (in blue).

When we run git rebase, it first will rewind both branches back to the first point when their commit history matches (in gray). From this point, git rebase will fast-forward through the commits on the master branch and apply them to the stale branch. Finally, git rebase replays the commits from the stale branch.

The resulting tree is as if you just created a new branch off master and made your commits. In doing so, git rebase facilitates a clean merge.

Changing a set of commits

I also like to use git rebase to change a set of commits. Often these are quick commits I made on a feature branch I want to clean up before merging. Either by condensing commits or improving their commit messages.

To do so, I'll run git rebase -i. The -i stands for interactive, because git rebase allows you to edit the commit list.

The output looks similar to the output from git log --oneline. However, each commit is prefixed with a command. The comments contain a legend for each of the commands.

Commit message from git rebase -i

I'll commonly use r to reword a quick commit and f to fixup a commit into the previous commit without changing the message. Although many people talk about squashing a commit, I use fixup far more often than squash as the latter requires an extra step of editing the commit messages.

Upon saving, git rebase -i will replay these commits using the commands you specified.

A few caveats

  • There can be conflicts.
  • The replayed commits get a new commit SHA.

If you're making small, cohesive commits (as outlined in When to make a Git commit) any conflicts should be easy to resolve.

Finally, it's important to note that git rebase will change the SHA of any replayed commits. So if you shared your commits with others or merged them into another branch, Git will no longer see these commits as being the same.

Want to Master more Git commands? This post was adapted from my video series Getting Git. It contains over 50 videos covering Git commands as well as scenarios you'll encounter using Git every day. The Master: git rebase is available on Vimeo.

Top comments (16)

Collapse
 
tmr232 profile image
Tamir Bahar

Just remember to always git branch backup before you rebase. Then, after the rebase, you can git diff backup to make sure it went well. If something does go awry, you can just git reset --hard backup and start over.

Collapse
 
obscuren profile image
Jeffrey Wilcke

There's no need to create a backup branch. You can do git diff HEAD@{N}~range and git reset --hard HEAD@{N}. Also see git reflog

Collapse
 
tmr232 profile image
Tamir Bahar

I agree. But from my experience, people just learning how to rebase really don't want to know anything about git reflog.
The branch method is simpler for beginners.

Collapse
 
jandedobbeleer profile image
Jan De Dobbeleer

You can also use git commit --fixup <hash> to prepare a fixup (or squash using --squash). They will be added on top of your branch so you still have to do a rebase using git rebase -i --autosquash to do the fixup or squash. I use this a lot to quickly fix PR review comments or mistakes I made along the way.

Collapse
 
lt0mm profile image
Tom • Edited


git commit --amend --no-edit

is also useful in such cases, which simply adds your changes to previous commit,


 tells git to leave previous commit message
Collapse
 
jandedobbeleer profile image
Jan De Dobbeleer

Yup, but that only goes for the last commit whereas a fixup can blend into any commit after a rebase.

Thread Thread
 
lt0mm profile image
Tom

Really neat, I didn't understand initially what it is

Thread Thread
 
jeklah profile image
Jeklah

Very useful when you're using cli to commit with a message, but the commit message turns out too long so you shorten it, then can go to --amend --no-edit to extrapolate on the initial brief commit message. This is my most common use for this.

My second is forgetting to mention a change in a commit.

Collapse
 
cheesechoker profile image
Angus MacAskill

git reflog works, but finding the original pre-rebase ref in the mass of reflog output that occurs during a rebase disaster can be difficult, especially for beginners.

I find it way easier to just create a backup branch, giving you an easily, visible "last good" ref you can quickly reset to. After all - this is git, branches are cheap!

Collapse
 
kaganasg profile image
Gary Kaganas

In the stale branch example, using the video editing metaphor, do the dates of commits on the base and branch influence how the branch merge is done? Do newer base commits get applied after older branch commits?

Collapse
 
gonedark profile image
Jason McCreary

No, the commit dates do not influence a rebase. The base branch commits are fast forwarded, then the stale branch commits are replayed.

Techically a replayed commit creates a new commit. So it has a new SHA and time stamp, and everything else is the same.

Collapse
 
mvonfrie profile image
Marco von Frieling

I agree that it is a much cleaner approach than merging feature branches into master (and master back into the feature branch to get changes from other branches and developers) and as well that squashing and rebasing helps to keep the history of master clean, e. g. by squashing work unit and WIP commits into a single or few feature commits on master. I found this post via How I Git, so my question might relate to that post as well.

But I have one caveat with this workflow:

How do I rebase my feature branch on top of master to get rid of it's stale status when it is remote tracked on GitHub or GitLab? And there are mainly three reasons to remote track a feature branch and regularly push it:

  • Having a backup of the code in case something happens my the local working copy or machine it is on.
  • Working on the same branch on different computers, e. g. office and home office or workstation and notebook.
  • More than one developer is working on a branch, maybe first the backend developer does all the business logic and then the frontend developer takes over to implement the UI.
Collapse
 
obscuren profile image
Jeffrey Wilcke

Try --onto as well, it's pretty neat. It allows you to rebase on a changed base branch (e.g. when the base has rebased itself).

Collapse
 
andydangerous profile image
Andy

Thanks for this!

Collapse
 
paul_melero profile image
Paul Melero

Thanks a lot, Jason. This is my guide, moreover man pages.

Collapse
 
vikramj74 profile image
Vikram Jaswal

Thanks for sharing the knowledge :)