A git rebase takes the commits on your branch and replays them one by one on top of a different base commit, rewriting them with new commit identifiers so the branch appears to have been developed from the latest state of the target branch. The result is a clean, linear history without the extra merge commits that merging produces. Rebase is powerful for tidying local work before sharing it, but because it rewrites history, it must be used carefully on anything others have seen.
Key takeaways
- Rebasing replays your commits onto a new base, producing new commit hashes and a linear history.
- Merge preserves history with a merge commit; rebase rewrites it for a cleaner, straight line.
- The golden rule: never rebase commits that have already been pushed to a shared branch.
- Interactive rebase lets you squash, reorder, edit, and drop commits to curate history.
- Conflicts are resolved commit by commit, then you continue the rebase.
- The reflog lets you recover if a rebase goes wrong, because old commits linger before garbage collection.
What does git rebase actually do?
Imagine your feature branch diverged from main several commits ago, and main has since gained new commits. A rebase reapplies your feature commits on top of the current tip of main, as if you had started your work from there. Git does this by temporarily setting aside your commits, moving your branch to the new base, and replaying each commit in order.
git switch feature
git rebase main
Crucially, each replayed commit is a new commit with a new hash, even if its content is identical, because a commit’s identity includes its parent. The original commits are not modified in place; they are recreated. This is why rebase is described as rewriting history.
What is the difference between rebase and merge?
Both integrate changes from one branch into another, but they produce different histories and serve different goals.
| Aspect | Merge | Rebase |
|---|---|---|
| History shape | Branching, with a merge commit | Linear, no merge commit |
| Commit hashes | Preserved | Rewritten |
| Records when integration happened | Yes | No |
| Best for | Shared branches, preserving context | Cleaning up local work before sharing |
Merge is non-destructive and truthful about what happened, which is why it suits public, shared branches. Rebase yields a tidy, easy-to-read line of commits, which is ideal for polishing a feature branch before opening a pull request. Many teams rebase local work, then merge the finished branch.
What is the golden rule of rebasing?
The single most important rule is: do not rebase commits that exist on a shared or public branch, or that others may have already based work on. Because rebasing replaces commits with new ones, anyone who already has the old commits will find their history diverged from yours.
If you rebase shared commits and force-push, collaborators face duplicated commits and painful reconciliation. Keep rebasing to:
- Local commits you have not pushed anywhere.
- A personal feature branch that only you work on, understanding a force-push is required.
For branches multiple people share, prefer merge. This one discipline prevents the large majority of rebase disasters.
How does an interactive rebase work?
Interactive rebase is where much of rebase’s value lies. It opens an editable list of commits and lets you decide what to do with each before they are replayed. Start it by specifying how far back to go:
git rebase -i HEAD~4
You then see the selected commits each prefixed with an action word you can change:
- pick keeps the commit as is.
- reword keeps the commit but lets you edit its message.
- squash combines the commit into the previous one, merging messages.
- fixup like squash but discards this commit’s message.
- edit pauses so you can amend the commit’s content.
- drop removes the commit entirely.
Common uses include squashing several work-in-progress commits into one clean commit, fixing a typo in an earlier commit message, or reordering commits into a logical sequence. This is how you turn messy local history into a reviewable story before sharing.
How do I resolve conflicts during a rebase?
Conflicts arise when a commit being replayed touches lines that also changed on the new base. Unlike a merge, which surfaces all conflicts at once, a rebase pauses at each conflicting commit so you resolve them incrementally.
The workflow is:
- Git stops and marks the conflicted files.
- You edit the files to resolve the conflict.
- Stage the resolved files with
git add. - Continue with
git rebase --continue.
You can also run git rebase --skip to drop the current commit if it is no longer needed, or git rebase --abort to stop entirely and return your branch to its state before the rebase started. Aborting is the safe escape hatch whenever a rebase becomes confusing.
How do I keep a branch up to date and push after rebasing?
A frequent use of rebase is to update a feature branch with the latest main so it applies cleanly. After fetching, rebase onto the updated base:
git fetch origin
git rebase origin/main
Because rebasing rewrote your already-pushed feature commits, a normal push is rejected as non-fast-forward. Use a force push, but the safer variant that refuses to overwrite unexpected remote work:
git push --force-with-lease
Prefer --force-with-lease over a plain --force because it checks that the remote branch is still where you expect, protecting a teammate who may have pushed in the meantime. Only do this on branches that are yours to rewrite.
How do I recover from a bad rebase?
Because rebase creates new commits and moves your branch pointer, the original commits are not immediately deleted. The reflog records where your branch pointed over time, so you can return to the pre-rebase state.
git reflog
git reset --hard HEAD@{5}
Find the entry that shows your branch just before the rebase began, then hard reset to it. The old commits reappear because they were never truly lost, only unreferenced. This safety net means you can experiment with rebasing more confidently, as long as you act before Git eventually garbage-collects unreachable commits. When unsure mid-rebase, git rebase --abort is the immediate way out.
When should I choose rebase over merge in a real workflow?
The decision comes down to who has seen the commits and what kind of history you want. A practical policy that many teams adopt is to rebase private work and merge public work.
- Before opening a pull request: rebase your feature branch onto the latest
mainand squash noisy commits so reviewers see a clean, logical series. - While a branch is shared: once teammates have pulled it, integrate updates with merge rather than rebase to avoid rewriting commits they already hold.
- Integrating a finished feature: merging into
mainrecords when the feature landed, which many teams value for traceability.
Some teams enforce a linear history by rebasing every feature before merge, while others prefer merge commits to preserve exact context. Neither is universally correct; what matters is consistency within the team and never rewriting shared commits. A useful middle ground is git pull --rebase, which replays your local commits on top of fetched upstream commits instead of creating a merge commit each time you sync, keeping local history tidy without affecting anyone else.
Frequently asked questions
What is a git rebase in simple terms?
A rebase moves or replays your commits onto a new base commit, rewriting them so your branch appears to have started from the latest state of the target branch.
What is the difference between rebase and merge?
Merge combines branches with a merge commit and preserves history as it happened, while rebase rewrites commits onto a new base for a linear history without a merge commit.
Is git rebase dangerous?
Rebasing is safe on local, unshared commits but risky on shared branches because it rewrites history, which forces collaborators to reconcile diverged commits.
What is the golden rule of rebasing?
Never rebase commits that others have already pulled or that exist on a shared public branch, because rewriting shared history disrupts everyone else.
What is an interactive rebase?
An interactive rebase lets you reorder, squash, edit, or drop commits before replaying them, giving fine control over how history is cleaned up.
How do I undo a rebase?
Use the reflog to find the commit your branch pointed to before the rebase and reset your branch back to it, since the old commits still exist for a while.
Why do I get conflicts during a rebase?
Conflicts occur when replaying a commit changes lines that the new base also changed. You resolve each, stage the fix, and continue the rebase.