Git rebase vs merge: what's the difference?
October 29, 2026 · 2 min read
A merge joins two branches with a new merge commit and keeps history as it happened. A rebase replays your branch's commits on top of the other branch, giving a straight line but new commits with new hashes.
Same branch, both ways
Make a main with one commit, a feature branch with two, then let main move on. Copy a branch for each approach:
git init -q -b main . && git commit -q --allow-empty -m "Start"
git switch -q -c feature
echo 1 > f1 && git add . && git commit -q -m "Add feature 1"
echo 2 > f2 && git add . && git commit -q -m "Add feature 2"
git switch -q main
echo m > m && git add . && git commit -q -m "Update main"
git branch merged feature
git branch rebased feature
git switch -q merged && git merge -q --no-edit main
git log --oneline --graph
git switch -q rebased && git rebase main
git log --oneline --graph
Output (your hashes will differ):
# merged
* 2dbcc3e Merge branch 'main' into merged
|\
| * ca91106 Update main
* | 634726a Add feature 2
* | a983be7 Add feature 1
|/
* b953081 Start
# rebased
* 446b31a Add feature 2
* ec73e41 Add feature 1
* ca91106 Update main
* b953081 Start
What changed
- Merge left both lines of work visible and added a merge commit. The feature commits kept their hashes (
634726a,a983be7). - Rebase made a linear history. Your two commits now sit after
Update main, and they have new hashes (ec73e41,446b31a), because a commit's hash includes its parent.
Use rebase to bring your own branch up to date before review. Use merge for a finished branch going into main, or any branch other people work on too.
The golden rule
Never rebase commits that other people already have. Their copies still hold the old commits, and when the histories meet, the same changes show up twice.
Common mistake
Rebasing a pushed branch, then running git push --force. Plain force overwrites whatever is on the remote, including a teammate's new commit. Use the safer form:
git push --force-with-lease
It refuses with stale info if the remote moved since your last fetch. If that happens, run git fetch, look at what arrived, and talk to your teammate before rewriting.
Also: if the push is rejected as non-fast-forward right after a rebase, that is expected. The remote still has the old commits.
Merge keeps history as it happened; rebase rewrites it into a straight line. Rebase only what's yours alone, and merge the rest.