Rebasing: Rewriting History Safely
Learn how git rebase replays your commits on top of another branch, how to tidy commits with interactive rebase, and the golden rule that keeps rebasing safe.
On this page 12 sections
Introduction
Merging records exactly what happened, including every branch split and join. That is honest, but on busy projects the history can turn into a tangle of merge commits. Rebasing is the alternative: it moves your branch so it starts from the latest commit of another branch, producing a clean, straight line. It is a powerful tool — and one with a single, important safety rule.
- What git rebase does to your commits.
- How to squash, reword and reorder commits with interactive rebase.
- How to handle conflicts during a rebase.
- The golden rule of rebasing, and when to merge instead.
The Situation
Priya adds a footer on a new branch in two commits — the second fixes a typo in the first. Meanwhile, she improves the page title on main. The branches have now diverged:
git log --oneline --graph --all -4Click Run to see what this code prints.
A merge would join them with a merge commit. Instead, she wants her footer commits to sit neatly on top of the latest main, as if she had started the branch after the title change.
Rebasing a Branch
Switch to the branch you want to move, then rebase it onto the other branch:
git switch feature/footergit rebase mainClick Run to see what this code prints.
git log --oneline --graph --all -4Click Run to see what this code prints.
The history is now a straight line. Look at the commit IDs, though: “Add footer” was 083f17a and is now 39a1fea. Rebasing does not move commits — it replays each change on top of the new starting point, creating brand-new commits, and then points the branch at them. The old commits are abandoned.
Interactive Rebase
Interactive rebase lets you edit a series of commits before sharing them: combine small fix-up commits, reword messages, reorder or drop commits. Priya’s “Fix typo in footer” commit adds nothing useful to the history, so she folds it into “Add footer”. HEAD~2 means “the last two commits”:
git rebase -i HEAD~2Git opens your editor with a to-do list, oldest commit first, followed by help text (shortened here):
pick 39a1fea # Add footerpick 63a934c # Fix typo in footer
# Rebase eefb9a7..63a934c onto eefb9a7 (2 commands)## Commands:# p, pick <commit> = use commit# r, reword <commit> = use commit, but edit the commit message# ...Change the word at the start of a line to tell Git what to do with that commit. Priya changes the second line from pick to fixup, then saves and closes the file:
pick 39a1fea # Add footerfixup 63a934c # Fix typo in footerClick Run to see what this code prints.
git log --oneline -3Click Run to see what this code prints.
| Command | What it does |
|---|---|
| pick | Keep the commit as it is |
| reword | Keep the commit but change its message |
| edit | Stop at this commit so you can change its contents |
| squash | Combine with the previous commit and edit the combined message |
| fixup | Combine with the previous commit and keep only the previous message |
| drop | Delete the commit |
Your branch has three commits: “Add login form”, “wip”, and “fix typo”. You have not pushed them. How do you turn them into a single clean commit called “Add login form”?
Finishing the Feature
Because the branch now starts from the tip of main, merging it is a simple fast-forward:
git switch maingit merge feature/footerClick Run to see what this code prints.
After deleting the merged branch with git branch -d feature/footer, the footer is one tidy commit on top of main:
git log --oneline --graph -6Click Run to see what this code prints.
Conflicts During a Rebase
Since a rebase replays commits one at a time, a conflict can stop it partway. Resolve it exactly as you would a merge conflict, then continue:
| Command | Use it when |
|---|---|
| git add <file> then git rebase --continue | You have fixed the conflict and want to replay the next commit |
| git rebase --skip | The commit is no longer needed (for example, the same fix is already on main) |
| git rebase --abort | You want to stop and put the branch back exactly as it was |
The Golden Rule
Rebasing replaces commits with new ones. If you rebase commits that you already pushed and that teammates have pulled, their history and yours no longer match, and untangling it is painful. Rebase only your own local commits — or a branch nobody else uses.
If you rebase your own branch after pushing it (for example, to tidy a pull request), a normal git push is rejected because the history changed. Use git push --force-with-lease, which only overwrites the remote branch if nobody else has pushed to it in the meantime. Never force-push to main or other shared branches.
Five teammates work on the shared develop branch. Priya runs git rebase -i on develop to clean up last week’s commits, then runs git push --force. What is wrong?
Merge or Rebase?
| Merge | Rebase | |
|---|---|---|
| History | Shows exactly what happened, including merge commits | Clean straight line, as if work happened in sequence |
| Rewrites commits? | No | Yes — creates new commits |
| Safe on shared branches? | Yes | No (golden rule) |
| Conflicts | Resolved once, in the merge | May need resolving once per replayed commit |
| Typical use | Bringing a finished feature into main | Updating your own feature branch, tidying commits before review |
Both are correct tools; teams usually pick a convention. A common one: rebase your own branch onto the latest main to keep it current, then merge it through a pull request. You can also make git pull rebase instead of merge with git pull --rebase.
Common Mistakes
- Rebasing a shared branch and force-pushing it.
- Using git push --force instead of --force-with-lease on your own branch.
- Panicking in the middle of a conflicted rebase — git rebase --abort always gets you back.
- Rebasing in the wrong direction: you rebase your feature onto main, not main onto your feature.
Frequently Asked Questions
Yes. The old commits still exist for a while. git reflog (lesson 16) lists where your branch pointed before the rebase, and git reset --hard <that-entry> restores it.
A commit’s ID is calculated from its contents, its message and its parent. Rebasing gives each commit a new parent, so every replayed commit gets a new ID.
No. Many successful teams only merge. Rebasing is a tool for keeping history readable; learn it so you can follow your team’s conventions and tidy your own work.
Key Takeaways
- git rebase main replays your branch’s commits on top of the latest main, creating new commits.
- git rebase -i lets you pick, reword, squash, fixup, reorder and drop commits.
- Resolve rebase conflicts, then git rebase --continue — or git rebase --abort to cancel.
- Golden rule: never rebase commits other people already have.
- If you must update your own pushed branch, use git push --force-with-lease, never on shared branches.
Summary
Priya’s history is clean, and she knows how to keep it that way. So far, though, everything has lived on one computer. In the next lesson she puts her portfolio on GitHub, and you will learn how push, pull and fetch keep copies of a repository in sync.