Every developer eventually runs into the same question: what is Git rebase, and why does it make some teammates nervous? It’s one of the most powerful commands in Git, and also one of the most misunderstood.
Rebase lets you rewrite commit history by replaying changes from one branch onto another. That sounds simple enough. But the details matter, because getting it wrong on a shared branch can cause real problems for your team.
This article breaks down how rebase works step by step, when to use it instead of merge, how interactive rebase cleans up messy commits, and what to do when conflicts show up. You’ll also learn the common errors developers hit and the best practices that keep distributed version control workflows running smoothly.
What is Git Rebase

Git rebase is a command that moves or replays commits from one branch onto another base commit. It rewrites commit history by taking a sequence of commits, detaching them from their original base, and reattaching them to a different point in the repository timeline.
The basic syntax looks like this: git rebase <base-branch>.
That single line does a lot. It tells Git to take every commit on your current branch that doesn’t exist on the target branch, temporarily set them aside, fast-forward your branch pointer to the tip of the target, and then replay each of those commits one by one on top.
The result? A perfectly linear history. No fork-and-merge pattern. Just a clean, straight line of commits as though all the work happened sequentially.
Git adoption has been climbing steadily for years. According to RhodeCode, 93.87% of developers used Git as their primary version control system by 2025, up from 87.1% in 2016. And within that population, rebase is one of the most discussed and debated commands.
Hutte research shows that 60% of professional developers use git rebase regularly to clean up their commit history. But here’s the tricky part. About 55% of those same developers also admit they find the command challenging and error-prone at times.
That tension tells you everything. Rebase is powerful and widely used, but it requires understanding what’s actually happening under the hood.
How Git Rebase Works Step by Step

Forget the theory for a second. Here’s what Git actually does when you run git rebase main from a feature branch.
Step one: Git identifies the common ancestor commit between your current branch and the target branch. This is the point where the two branches originally diverged.
Step two: Every commit you made on your feature branch after that divergence point gets temporarily removed. Git stores them as patches.
Step three: Your branch pointer moves forward to the tip of the target branch (in this case, main).
Step four: Git takes each of those stored patches and applies them one at a time on top of the new base. Each gets a brand new SHA hash.
That last detail catches people off guard. The commits look the same. They have the same diff, the same message. But they are technically new commits with new identifiers because the parent commit changed.
What Happens to Commit History During a Rebase
Your original commits don’t vanish immediately. They sit in Git’s reflog for a default period of 90 days.
But from the perspective of git log, the old branch structure disappears. What you see instead is a clean, linear sequence of new commits stacked on the updated base. The fork that used to exist between your branch and main is gone.
This is what people mean by “rewriting history.” The content of the changes is identical, but the commit graph tells a different story. Teams working across a shared codebase need to understand this distinction before using rebase on anything that’s been pushed to a remote repository.
Git Rebase vs. Git Merge

This is the comparison that comes up in every team standup and every Stack Overflow thread. Both commands integrate changes from one branch into another. They just do it differently.
| Aspect | Git Rebase | Git Merge |
|---|---|---|
| History shape | Linear, single line | Branched, with merge commits |
| Commit hashes | Creates new SHAs | Preserves original SHAs |
| Conflict resolution | Per commit (can repeat) | Once, at merge point |
| Safe for shared branches | No | Yes |
| Traceability | Loses merge context | Shows when features were integrated |
Hutte data shows 55% of developers prefer merging over rebasing for integrating changes. The reasoning? Merging is safer. It doesn’t rewrite anything. You run git merge feature-branch, Git creates a new merge commit, and both histories stay intact.
Rebase flattens everything into one timeline. That makes git log easier to read and git bisect more useful for tracking down bugs. But it comes at the cost of losing the explicit record of when a feature branch was created and when it got integrated.
Atlassian’s internal Stash development team landed on an interesting position: never rebase during a pull request, but use it freely during local development. That’s a common compromise.
The right choice depends on what your team values more. Clean readability or complete traceability. Most teams these days use both, depending on the context. Rebase locally, merge publicly.
Interactive Rebase

Standard rebase moves commits. Interactive rebase lets you edit them.
Running git rebase -i HEAD~5 opens your text editor with a list of the last five commits. Each line starts with the word pick, followed by the commit hash and message. From there, you can change what happens to each one.
This is where rebase turns from a branch management tool into a history editing tool. And honestly, interactive rebase is the feature that most developers are actually talking about when they say “rebase.”
Common Interactive Rebase Commands Explained
pick: Keep the commit as-is. This is the default for every line.
reword: Keep the commit but open an editor to change the commit message. Took me way too long to discover this one existed.
squash: Combine this commit with the one above it and merge both commit messages together.
fixup: Same as squash, but throw away this commit’s message. Use it when the commit was a typo fix or a “WIP” that doesn’t deserve its own entry.
edit: Pause the rebase at this commit so you can amend its content. Useful when you realize you left a debug statement in an older commit.
drop: Remove the commit entirely from the branch history.
In practice, pick, squash, and fixup cover about 90% of what you’ll use. The rest are for more specific cleanup scenarios.
Tools like VS Code, JetBrains IDEs, GitKraken, and SourceTree all provide visual interfaces for interactive rebase. If the terminal list of commits feels intimidating, these GUIs make the process much more approachable. You drag, drop, and select actions from a menu instead of editing text in Vim.
Companies like Apple, Google, and Amazon use the Tower Git client, which handles interactive rebase through a right-click context menu. Over 100,000 developers use it specifically because rebase can be clunky on the command line.
When to Use Git Rebase

Rebase shines in specific situations. Using it outside those situations is where people get into trouble.
Keeping a Feature Branch Up to Date
This is the most common and least controversial use case. You’re working on a feature branch. Meanwhile, teammates have pushed new commits to main. Instead of merging main into your branch (which creates a merge commit every time), you run git rebase main.
Your feature branch stays current, and the history stays linear. The DEV Community’s 2026 Git workflow guide recommends this exact pattern: prefer rebase for keeping feature branches up to date with main before opening a PR.
Cleaning Up Local Commits Before Pushing
You’ve been working all day. You have 12 commits. Half of them say “WIP” or “fix typo” or something equally unhelpful.
Before pushing, run git rebase -i to squash those into two or three meaningful commits. Your reviewers will thank you. According to Hutte, 85% of collaborative projects use pull or merge requests in their workflow, which means clean commit history directly impacts how quickly your code gets reviewed.
Contributing to Open Source
Most open source projects on GitHub expect contributors to submit clean, rebased branches. Some projects explicitly enforce a “one PR = one commit” rule.
If you submit a pull request with 15 messy commits to a popular repository, the maintainer will either ask you to squash them or do it themselves. Rebasing before you push saves everyone’s time.
This pattern fits well within broader software development best practices around keeping project history clean and readable. It’s not just about aesthetics. A clean log makes debugging, reverting, and auditing significantly easier during the software development process.
When Not to Use Git Rebase

There’s one rule that every Git tutorial, every senior engineer, and every Atlassian blog post agrees on.
Never rebase commits that have been pushed to a shared branch.
That’s the golden rule. Break it, and you’ll understand why people call rebase “dangerous.”
Why Rebasing Shared History Breaks Things
Here’s what happens. You push five commits to a branch. Your teammate pulls those commits and starts building on top of them. Then you rebase locally, which creates five new commits with new SHA hashes. The originals are gone from your branch.
When you force-push, your teammate’s branch now references commits that no longer exist on the remote. Git can’t reconcile this. The result is duplicated commits, broken merges, and a lot of frustration in Slack.
Atlassian’s documentation puts it bluntly: rewriting history of shared branches is prone to team work breakage.
Force Push and Its Risks
After rebasing a branch that was already pushed, Git will reject a normal git push because the histories have diverged. The only way forward is a force push.
Plain --force is the sledgehammer approach. It overwrites the remote branch completely, regardless of what’s there. If a colleague pushed a commit between your pull and your force push, that commit is gone.
The safer alternative is --force-with-lease. This checks that the remote branch hasn’t changed since your last fetch. If someone else has pushed in the meantime, the operation fails instead of overwriting their work.
Any team using rebase in their Git workflow should enforce --force-with-lease as a standard. Some teams configure source control management policies to block plain force pushes entirely through server-side hooks.
With over 100 million developers now on GitHub alone (Statista, 2023), the chances of someone else touching the same branch you’re rebasing have never been higher. Rebase locally. Merge publicly. Your team will be better off for it.
How to Handle Rebase Conflicts

Conflicts during a rebase work differently than merge conflicts. And that difference is what makes them more tedious.
When you merge, Git shows you all conflicts at once. You fix everything in a single pass, commit, and move on. Rebase doesn’t work that way. It replays each commit individually, which means you might hit a conflict on commit two, resolve it, continue, and then hit another conflict on commit four.
Hutte research shows 87% of Git users have encountered merge conflicts at some point. Developers spend roughly 10% of their Git time on conflict resolution alone.
The Three Options During a Conflict
| Command | What It Does | When to Use |
|---|---|---|
git rebase --continue | Proceeds after you fix the conflict | After resolving and staging files |
git rebase --skip | Drops the current commit entirely | When the commit is no longer needed |
git rebase --abort | Cancels the rebase and restores the original state | When things go sideways |
The --abort option is your safety net. If you’re three commits deep into a messy rebase and nothing looks right, abort and start fresh. No harm done.
Why Rebase Conflicts Feel Worse Than Merge Conflicts
The repetition is what gets you. Because Git applies each commit one at a time, you can end up fixing the same file in the same spot across multiple commits. Merge would have shown that conflict once.
Git has a built-in tool for this called rerere (reuse recorded resolution). Enable it with git config --global rerere.enabled true, and Git remembers how you resolved a conflict so it can automatically apply the same fix next time.
Databricks added rebase and conflict resolution directly into their Repos UI, letting data engineers resolve conflicts visually without leaving their workspace. That’s a sign of how routine this problem has become.
Keeping commits small and atomic reduces the chances of repeated conflicts. Hutte data shows 80% of senior developers recommend committing changes frequently with small, incremental commits. That advice becomes even more relevant when you’re rebasing regularly.
Git Rebase onto a Specific Commit

Standard rebase moves your entire branch to the tip of another branch. The --onto flag gives you finer control.
The syntax looks like this:
git rebase --onto <new-base> <old-base> <branch>
Three arguments. That’s what trips people up. But once you understand what each one does, it clicks.
First argument: where you want the commits to land (the new parent).
Second argument: the point after which commits should be taken (the old parent, exclusive).
Third argument: the branch containing the commits you want to move. If omitted, Git uses the current HEAD.
When –onto Solves Problems Regular Rebase Cannot
Moving a branch from one parent to another. You accidentally branched off feature-A instead of main. Running git rebase --onto main feature-A transplants your work onto the correct base without dragging along feature-A’s commits.
Removing a range of commits. If you need to cut commits 3 through 5 from a branch while keeping everything else, --onto lets you specify exactly which range to skip. The VMware Tanzu engineering blog documents this pattern for cleaning up accidental dependencies between stacked branches.
This kind of precision is why --onto is considered an advanced tool. Most developers won’t need it daily. But when you do need it (and you will), git log and git rev-parse become your best friends for finding the right commit hash values.
Git Rebase Best Practices

The rules are straightforward if your team agrees on them upfront. Most of the pain around rebase comes from inconsistent habits across a team, not from the command itself.
Rebase Locally, Merge Publicly
This is the consensus that most development teams have landed on. Use rebase to keep your personal feature branches clean. Use merge when integrating into shared branches like main or develop.
The 2026 DEV Community Git workflow guide puts it simply: rebase for keeping feature branches up to date before opening a PR, merge for integrating completed work.
Hutte data shows 92% of projects using Git enforce code review before merging changes. That review process works best when the commit history is already clean.
Use git pull –rebase Instead of git pull
A normal git pull creates a merge commit every time your local branch is behind the remote. Over a week, that’s a dozen pointless merge commits cluttering your log.
Running git pull --rebase replays your local commits on top of the fetched changes instead. No merge commit. Clean linear history.
To make this the default, run:
git config --global pull.rebase true
Atomic Object’s engineering team lists this as one of three Git config settings that should be enabled by default on every developer machine. Also worth enabling: rebase.autoStash, which automatically stashes uncommitted changes before a rebase and pops them after.
Squash Before Merging Feature Branches
GitHub, GitLab, and Bitbucket all offer “squash and merge” as a pull request option. It takes all your feature branch commits and compresses them into a single commit on the target branch.
- One feature, one commit on main
- Clean
git logfor anyone reading the history later - Easier to revert an entire feature if something breaks
GitHub’s own merge interface offers three strategies: merge commit, squash and merge, or rebase and merge. Teams working within continuous integration pipelines often default to squash and merge because it keeps the main branch history predictable for automated build pipeline triggers.
Standardize Across the Team
Pick a strategy and document it. The worst situation is half the team rebasing and the other half merging with no agreement on when to use which.
According to Hutte, 75% of larger teams establish commit message guidelines to keep things clear. That same discipline should extend to branch integration strategy. A simple rule in a design document or team wiki removes ambiguity for new hires and contractors.
Common Git Rebase Errors and How to Fix Them

Rebase errors don’t usually mean something is broken. They usually mean Git is stopping to ask you a question, and you haven’t answered it yet.
“Cannot rebase: You have unstaged changes”
Git won’t start a rebase if your working directory isn’t clean. Two quick fixes:
- Run
git stashbefore rebasing, thengit stash popafter - Enable
rebase.autoStash truein your Git config to handle this automatically
Hutte data shows 52% of developers use git stash when saving changes without committing. If you rebase frequently, auto-stash is the better approach.
Recovering from a Bad Rebase with git reflog
Don’t panic. Every action in Git is recoverable through the reflog.
Run git reflog to see a timestamped list of every HEAD movement. Find the entry from right before the rebase started. Then run git reset --hard <ref> to restore your branch to that exact state.
The reflog keeps entries for 90 days by default. That’s a generous window. Even if you realize a rebase went wrong three weeks later, the recovery path is the same.
Diverged Branches After a Force Push
You rebased a branch that was already pushed. Now Git says your local and remote branches have “diverged.” This is expected behavior, not an error.
The fix is git push --force-with-lease. It overwrites the remote branch, but only if nobody else has pushed to it since your last fetch.
Hutte research shows 45% of developers have been negatively affected by a colleague’s force push. Using --force-with-lease instead of plain --force prevents the most common disaster scenario.
The Difference Between –force and –force-with-lease
| Flag | Behavior | Safety Level |
|---|---|---|
--force | Overwrites remote branch regardless of state | Dangerous |
--force-with-lease | Overwrites only if remote hasn’t changed since last fetch | Safe for personal branches |
Some teams configure server-side hooks on GitHub or GitLab to reject plain force pushes on protected branches entirely. That’s a good software configuration management practice that prevents accidental history loss on shared branches like main or release.
The Linux kernel project, which Linus Torvalds originally built Git for, relies heavily on rebasing during patch review. But even in that project, direct force pushes to the mainline repository are prohibited. Rebase is a local tool first, and that’s where it works best.
FAQ on What Is Git Rebase
What does Git rebase actually do?
Git rebase moves commits from one branch onto a new base commit. It replays each change sequentially, creating new commits with new SHA hashes. The result is a linear commit history without merge commits cluttering the log.
Is Git rebase safe to use?
Rebase is safe for local, unpushed branches. It becomes risky when applied to shared branches because it rewrites commit history. The golden rule: never rebase commits that other developers have already pulled from a remote repository.
What is the difference between Git rebase and Git merge?
Merge creates a new merge commit and preserves both branch histories. Rebase replays your commits on top of another branch, producing a clean linear history. Merge is safer for shared branches. Rebase is better for local cleanup.
What is interactive rebase in Git?
Interactive rebase (git rebase -i) opens an editor listing commits you can modify. You can squash, reword, reorder, edit, or drop individual commits. It’s the primary tool for cleaning up messy commit history before a pull request.
When should I use Git rebase instead of merge?
Use rebase to keep a feature branch updated with main, clean up local commits before pushing, or prepare branches for open source contributions on GitHub. Use merge when integrating completed work into shared branches like main or develop.
How do I resolve conflicts during a rebase?
Fix the conflicting files manually, then run git add followed by git rebase --continue. If things go wrong, git rebase --abort cancels everything and restores the original branch state. Conflicts may repeat across multiple commits.
What does git rebase –onto do?
The --onto flag lets you move commits to a specific base commit rather than the tip of a branch. It takes three arguments: new base, old base, and branch. It’s useful for transplanting branches or removing specific commits.
Can I undo a Git rebase?
Yes. Run git reflog to find the state before the rebase started. Then use git reset --hard with that reference to restore your branch. The reflog keeps entries for 90 days by default, giving you a generous recovery window.
What does git pull –rebase do?
It fetches remote changes and replays your local commits on top instead of creating a merge commit. Running git config --global pull.rebase true makes this the default behavior. It keeps your branch history linear without extra merge commits.
Why do people say rebase is dangerous?
Because it rewrites commit history. If you rebase commits that were already pushed and shared, teammates working on those same commits will encounter duplicated or missing changes. Force pushing after a rebase on shared branches can overwrite other people’s work.
Conclusion
Understanding what is Git rebase comes down to one thing: knowing when to use it and when to leave it alone. It’s a tool for rewriting commit history, keeping feature branches clean, and producing a linear project timeline that’s easier to read and debug.
The practical takeaway is simple. Rebase locally on your own branches. Merge when pushing to shared repositories on GitHub, GitLab, or Bitbucket. Use interactive rebase to squash commits before opening a pull request. And always prefer –force-with-lease over plain force push.
Configure git pull –rebase as your default. Enable rerere` for automated conflict resolution. Keep commits small and atomic.
These habits turn rebase from something intimidating into a routine part of your source control workflow. Get comfortable with the reflog as your safety net, and rebase stops being scary.
- How to Make a Repository Private in GitHub - July 20, 2026
- How to Set Up Google Play Family Library - July 18, 2026
- How to Run Pytest in PyCharm: A Complete Walkthrough - July 16, 2026



