Thuta Learning
AdvancedDevOps & Toolsintermediate

Rebase, and Merge vs Rebase

What you'll walk away with

  • Explain the core ideas behind Rebase, and Merge vs Rebase
  • Read the diagram and trace how state or data flows through the Git/GitHub workflow
  • Decide how this applies to your own project or team

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.

ApproachWhat happens
MergeNon-destructive: never rewrites commits, preserves full branch history including side branches, but adds merge commits and a busier graph.
RebaseProduces 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.
text
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

bash
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 --oneline
You should see
Before 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 DocumentationGit & GitHub

Easy traps

  • 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.
  • Always run `git status` before any destructive or history-rewriting command, to know exactly what state you're in.

Exercise

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.

You'll know it worked when: Before 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.