What is "git rebase"?

TL;DR
For those in a hurry, here’s the quick takeaway on git rebase:
- What it is: A git command that moves a sequence of commits from one branch onto another, creating a cleaner, more linear project history.
- Use it when you want to:
- Keep your project history clean and linear.
- Incorporate the latest changes from another branch without creating a merge commit.
- Prepare your branch for a pull request by cleaning up your commits.
- The Golden Rule: Only use git rebase on local branches that you haven't shared with others. Rebasing public or shared branches can cause significant issues for your collaborators.
The long answer -
In the world of software development, git
is an indispensable tool. While most developers are familiar with the basic commands like git add
, git commit
, and git push
, there are more advanced features that can significantly improve your workflow. One of the most powerful, yet often misunderstood, of these is git rebase
.
Many developers are told to avoid it like the plague, while others swear by it. I am generally one of those senior devs who would always tell junior devs in the team to simply use git merge and not try to use git rebase
, if fact I myself in 10+ years of my professional career didn't have to use git rebase
. So what’s the real story? Let's demystify git rebase once and for all.
What is git rebase
?
Git rebase is a command that allows you to move or replay a sequence of commits from one branch onto another. In simpler terms, it rewrites the history of your branch by pretending your work started from a different point—a different "base."
Instead of merging two branches together, which creates a new "merge commit" to combine their histories, rebase transplants your commits as if they were created on top of the latest state of another branch, like main or master.
This results in a much cleaner, linear commit history, making it easier to follow the progression of work.
Here’s a simple visualization:
Before Rebase:
Generated code
D---E---F (feature-x)
/
A---B---C (main)
In this scenario, you started working on feature-x from commit B. While you were working, new commits (C) were added to the main branch.
After Rebasing feature-x onto main:
Generated code
D'---E'---F' (feature-x)
/
A---B---C---G (main)
After running git rebase main from the feature-x branch, your feature commits (D, E, F) are re-applied after the latest commit on main (G). Notice that the commit hashes are new (indicated by D', E', F'), which is a crucial point we'll come back to.
How a Rebase Actually Happens
Conceptually, a git rebase works in three major steps:
- Find the Common Ancestor: Git identifies the last shared commit between your current branch (e.g., feature-x) and the branch you're rebasing onto (e.g., main). This is called the "merge base."
- Extract Your Commits: Git finds all the commits on your branch that came after this common ancestor and temporarily saves them as patches.
- Replay the Commits: Git moves your branch pointer to the tip of the target branch (e.g., main) and then reapplies each of your saved commits, one by one, on top of it.
This process is why the commit hashes change. Each "replayed" commit is technically a new commit with a different parent, even if the content of the changes is identical.
git rebase vs. git merge: What’s the Difference?
The main difference lies in how they handle project history.
git rebase is reconstructive. It linearizes the history by replaying commits, which results in a cleaner log but rewrites the commit history.
Rebase History:Generated code
A---B---C---G---D'---E'---F' (main)
git merge is non-destructive. It preserves the original branching history and adds a new merge commit to tie the histories together. This is safe for shared branches but can lead to a cluttered and hard-to-read commit log.
Merge History:Generated code
D---E---F
/ \
A---B-----------M---G (main)
\ /
C-------'
The Dangers of git rebase: The Golden Rule
Because git rebase rewrites history, it comes with a critical rule: Do not rebase commits that you've already pushed to a shared or public branch.
If you rebase a branch that others are working on, their history will diverge from the new history you've just created. This will lead to conflicts and potential loss of work when they try to pull the new changes.
As a rule of thumb:
- It's okay to rebase your own local feature branches that you haven't shared. This is like working in your own private sandbox.
- It's very dangerous to rebase shared branches like main, dev, or any other branch that multiple developers collaborate on.
Interactive Rebase: The Power User’s Tool
For even more control, you can use interactive rebase with the -i flag (git rebase -i). This opens a text editor with a list of the commits that are about to be replayed, allowing you to:
- Reorder commits.
- Squash multiple commits into a single, meaningful one.
- Edit commit messages.
- Drop or delete commits entirely.
This is an incredibly powerful tool for cleaning up your commit history before creating a pull request, ensuring that your changes are presented in a logical and easy-to-review manner.
In my career, I have seen developers messing up git history by using git rebase more often than using it to keep the git history clean. So I would still stick to my advice of using git merge over git rebase unless there is a specific mention of keeping the git history clean.