Git Merge vs Rebase — A Calculator App Case Study

Merge preserves history and creates a merge commit. Great for shared branches (like a team feature branch) and audit trails.
Rebase rewrites history to make it linear, as if your work started from the latest
main
. Great for your own local branches before you publish them.With 5 developers pushing to the same feature branch, prefer merging
main
into that shared branch. Use rebase for individual dev branches before they push.
The scenario
You’re building a Calculator application.
main
already has 100 commits.You created a feature branch:
feature/complex-cal
, with 5 developers collaborating on it. They make around 100 commits on this branch.While they’re working,
main
moves forward with another 75 commits.
Now you need to bring the latest from main
into feature/complex-cal
so you can integrate safely and resolve conflicts early. Do you merge or rebase?
What merge does (no history rewrite)
Merge takes two histories and ties them together with a merge commit. Your feature branch’s existing commits stay exactly as they were; Git just creates a new commit connecting both histories.
# from inside feature branch
git checkout feature/complex-cal
git fetch origin
git merge origin/main
Why teams like it
No history rewrite → safe for shared branches with many developers.
Clear audit trail: you can see when you integrated
main
.Conflict resolution happens once in the merge commit, visible to all.
How it looks:
gitGraph
commit id: "M1" tag: "main@100"
branch feature/complex-cal
checkout feature/complex-cal
commit id: "F1"
commit id: "F2"
checkout main
commit id: "M2"
commit id: "M3" tag: "main@175"
checkout feature/complex-cal
merge main tag: "Merge main->feature"
commit id: "F3"
What rebase does (history rewrite → linear)
Rebase takes your feature branch commits and replays them on top of the latest main
tip, creating new commit IDs. The result is a linear history as if you started from the newest main
.
# from inside your feature branch
git checkout feature/complex-cal
git fetch origin
git rebase origin/main
If conflicts happen:
git add <files>
git rebase --continue
# or
# git rebase --skip
# git rebase --abort
After rebase, force-push safely:
git push --force-with-lease
How it looks (after rebase):
gitGraph
commit id: "M1" tag: "main@100"
commit id: "M2"
commit id: "M3" tag: "main@175"
branch feature/complex-cal
checkout feature/complex-cal
commit id: "F1p"
commit id: "F2p"
Key differences
History shape: Merge → branching graph. Rebase → straight line.
Safety: Merge → safe for shared branches. Rebase → risky on shared branches.
Commit IDs: Merge → preserved. Rebase → rewritten.
Conflicts: Merge → once, at merge. Rebase → per commit during replay.
Logs: Merge → branchy. Rebase → clean linear.
Which one should you use?
You have 5 developers pushing to the same
feature/complex-cal
. That’s a shared branch.main
moved ahead by 75 commits while feature added ~100 commits.
Recommended:
Use merge regularly to bring
main
into the shared feature branch.Developers can rebase their personal work branches before pushing.
When the feature is done, merge it back into main (with
--no-ff
if you want to keep the boundary visible).
Flowcharts
1) git fetch
workflow
flowchart LR
subgraph FETCH [git fetch Workflow]
F1([Run: git fetch]) --> F2[Contact remote repo]
F2 --> F3[Download latest commits and branches]
F3 --> F4[Update remote-tracking refs: origin/main]
F4 --> F5[Local branch stays the same]
F5 --> F6[You decide: merge or rebase manually]
end
2) Sync with merge
flowchart LR
subgraph MERGE [Sync feature with main via MERGE]
A1([Checkout feature/complex-cal]) --> A2[git fetch origin]
A2 --> A3[git merge origin/main]
A3 --> A4{Conflicts?}
A4 -- No --> A5[Merge commit created]
A4 -- Yes --> A6[Resolve conflicts]
A6 --> A7[git add .]
A7 --> A8[git commit]
A8 --> A5
A5 --> A9[Commit IDs preserved]
A9 --> A10[Push: git push]
end
3) Sync with rebase
flowchart LR
subgraph REBASE [Sync feature with main via REBASE]
B1([Checkout feature/complex-cal]) --> B2[git fetch origin]
B2 --> B3[git rebase origin/main]
B3 --> B4{Conflicts?}
B4 -- No --> B8[Linear history created]
B4 -- Yes --> B5[Resolve conflicts per commit]
B5 --> B6[git add <files>]
B6 --> B7[git rebase --continue]
B7 --> B4
B8 --> B9[Force push safely]
end
Bottom line
Use merge for shared branches (your team’s
feature/complex-cal
).Use rebase on personal/local branches before pushing.
Both are correct; choose based on team workflow and safety.
Subscribe to my newsletter
Read articles from Chandra Sekhar directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
