Build the mental model
Rebase is a Git operation that takes the commits you made on your branch and replays them, one by one, on top of a different base commit, typically the latest commit on main. Instead of creating a merge commit, rebase rewrites your branch so it looks like you started from the newer base all along, producing a linear history instead of a merging graph.
The catch: replaying a commit does not reuse its original object, it creates a brand new commit with a new hash, because the parent changed and a hash is derived from content, metadata, and parent. Every commit on the rebased branch gets a new identity, even though the code changes stay exactly the same.
| Approach | What happens |
|---|---|
| Merge | Non-destructive: never rewrites commits, preserves full branch history including side branches, but adds merge commits and a busier graph. |
| Rebase | Produces a clean, linear history that's easier to review, but rewrites the hash of every replayed commit. |
Neither approach is universally correct; many teams merge feature branches into main but freely rebase their own local work before pushing.
Never rebase shared history
If a commit has already been pushed to a branch other people pull from, rebasing it creates duplicate commits with different hashes for everyone who already has the old ones. Only rebase local, unpushed commits — unless your entire team has explicitly agreed to coordinate around a force-push.
- Rebase
- A Git operation that replays a sequence of commits from one base commit onto another, creating new commit objects (and new hashes) with identical content changes.
REBASE: REPLAYING COMMITS ONTO A NEW BASE
-----------------------------------------
BEFORE REBASE
main: A---B---C
\
feature: D---E
AFTER REBASE (feature rebased onto main)
main: A---B---C
\
feature: D'---E'
Same code changes, new commit hashes: D' and E' are new objects.Connect it to a real scenario
This example builds a small repo where main and a feature branch both move forward independently, then rebases the feature branch onto the updated main.
Diverge
Commit A and B on main, branch feature from B, add commits D and E on feature while main gets its own commit C.
Inspect before
git log --oneline on feature shows A, B, D, E — unaware C ever happened.
Rebase
git rebase main replays D and E on top of C, producing D' and E' with new hashes.
Conflicts
If a conflict occurs mid-replay, Git pauses and lets you resolve it, then continue with git rebase --continue, one commit at a time.
Never rebase shared history
If a commit has already been pushed to a branch other people pull from, rebasing it creates duplicate commits with different hashes for everyone who already has the old ones. Only rebase local, unpushed commits — unless your entire team has explicitly agreed to coordinate around a force-push.
Try the working example
export GIT_AUTHOR_NAME="Thuta Learner"
export GIT_AUTHOR_EMAIL="learner@example.com"
export GIT_COMMITTER_NAME="Thuta Learner"
export GIT_COMMITTER_EMAIL="learner@example.com"
git init
export GIT_AUTHOR_DATE="2026-01-01T09:00:00"
export GIT_COMMITTER_DATE="2026-01-01T09:00:00"
echo "# Project" > README.md
git add README.md
git commit -m "A: initial commit"
export GIT_AUTHOR_DATE="2026-01-01T10:00:00"
export GIT_COMMITTER_DATE="2026-01-01T10:00:00"
echo "core logic" > app.js
git add app.js
git commit -m "B: add app.js"
git checkout -b feature
export GIT_AUTHOR_DATE="2026-01-01T11:00:00"
export GIT_COMMITTER_DATE="2026-01-01T11:00:00"
echo "feature part 1" > feature.js
git add feature.js
git commit -m "D: start feature"
export GIT_AUTHOR_DATE="2026-01-01T12:00:00"
export GIT_COMMITTER_DATE="2026-01-01T12:00:00"
echo "feature part 2" >> feature.js
git add feature.js
git commit -m "E: finish feature"
git log --oneline
git checkout main
export GIT_AUTHOR_DATE="2026-01-01T13:00:00"
export GIT_COMMITTER_DATE="2026-01-01T13:00:00"
echo "hotfix" > hotfix.js
git add hotfix.js
git commit -m "C: hotfix on main"
git checkout feature
git rebase main
git log --onelineBefore rebasing, git log --oneline on feature shows:
d0454cd E: finish feature
903b723 D: start feature
3d4128d B: add app.js
ad48fd4 A: initial commit
After committing C on main and running git rebase main on feature, the same command shows:
13d1c09 E: finish feature
bdf110d D: start feature
5c375f6 C: hotfix on main
3d4128d B: add app.js
ad48fd4 A: initial commit
D and E were replayed after C and got entirely new hashes (13d1c09 and bdf110d), while A, B, and C keep their original hashes.5-minute try-it
Create a repo with two diverging branches of your own (main and a feature branch each with new commits), then rebase the feature branch onto main. Run git log --oneline --graph on both branches before and after to see the shape change. Then try introducing a real conflict — edit the same line of the same file differently on both branches — and resolve it with git rebase --continue.
One important caution
Rebasing a branch that a teammate already pulled quietly duplicates every commit they still have, since the replayed commits get new hashes; the fix isn't a git command, it's a conversation before you rebase.
Force-pushing a rebased branch to a shared remote without warning anyone can silently discard a teammate's in-progress commits that were built on the old hashes.
Git - git-rebase Documentation — Git & GitHub