Merge vs Rebase — The Big Debate
Chay ki dukan pe debate khatam nahi hota, lekin code pe faisla karna padta hai.
When branches diverge — different commits on the same base — you must combine them eventually. You cannot ignore divergence forever; at some point, the code needs to live together.
Git gives you TWO ways to combine branches: git merge and git rebase. Both produce the same code result, but they create different histories.
git merge: creates a new "merge commit" that has TWO parents. It preserves the complete history exactly as it happened — every branch, every parallel line of development.
git rebase: replays your commits on top of the other branch. It creates a linear history as if you wrote the code sequentially, one commit after another. No merge commit.
The debate is not about which is "better" — it is about which history your team prefers.
# MERGE approach — preserves branch history
git checkout main
git merge feature
# Creates: A---B---C main timeline
# \ / (merge commit with 2 parents)
# D feature timeline
# REBASE approach — linear history
git checkout feature
git rebase main
# Creates: A---B---C---D' feature timeline
# All feature commits are replayed on top of main
# No merge commit, as if feature was written after Cgit merge is NON-DESTRUCTIVE — it never changes existing commits, only adds a new one.
Fast-forward merge: if main hasn't changed since you branched, Git just moves the pointer forward. No merge commit needed — it's as if the branch never existed.
3-way merge: if main has new commits, Git finds the common ancestor of both branches and creates a merge commit that combines both histories.
Merge commits have two parents — you can always trace both branches' histories. This is why merge is called "safe": nothing is lost, nothing is rewritten.
Use --no-ff to FORCE a merge commit even when fast-forward is possible. This preserves branch topology — evidence that a feature branch existed.
Pros: safe, preserves true history, reversible, team-friendly.
Cons: history becomes a "spaghetti" graph with many merge commits, harder to read, git log is noisy.
# Fast-forward merge (main hasn't changed)
git checkout main
git merge feature
# Fast-forward — main pointer just moves to feature tip
# 3-way merge (main has new commits)
git checkout main
git merge feature
# Merge made by the 'ort' strategy.
# Creates a merge commit with 2 parents
# Force merge commit (preserve branch evidence)
git merge --no-ff feature
# Even if fast-forward possible, creates merge commit
# Useful: shows where feature started and ended
# View merge history
git log --oneline --graph
# * abc1234 Merge branch 'feature'
# |\
# | * def5678 feature commit 2
# | * ghi9012 feature commit 1
# * jkl3456 main commitgit rebase MOVES your commits to a new base — it REWRITES history.
Process: Git temporarily removes your commits, updates your branch to the target, then re-applies your commits one by one on top of the new base.
Your old commits are DESTROYED and new ones are created with NEW SHA hashes — even if the code content is identical.
Rebase NEVER creates merge commits. History is perfectly linear.
Pros: clean history, easy to read, git log is a straight line, git bisect works better.
Cons: DANGEROUS on shared branches — if someone based work on your old commits, they're now broken.
The Golden Rule: NEVER rebase commits that have been pushed to a shared branch.
# Rebase your feature on top of main
git checkout feature
git rebase main
# First, rewinding head to replay your work on top of it...
# Applying: feature commit 1
# Applying: feature commit 2
# Your old commits are gone, new ones created
git log --oneline
# abc1234 feature commit 2 ← NEW hash
# def5678 feature commit 1 ← NEW hash
# ghi9012 main latest
# The old commits (with old hashes) no longer exist on this branch
# If conflicts occur during rebase
# CONFLICT (content): Merge conflict in file.txt
# Fix conflicts, then:
git add file.txt
git rebase --continue
# To abort and go back: git rebase --abort
git merge --squash feature: takes ALL feature commits and combines them into ONE new commit on main.
No merge commit, no feature branch history visible — just one clean commit.
Use when: feature has 20 messy "WIP" commits that don't matter to main's history.
Process: git merge --squash feature → changes go to staging area → you commit manually.
Unlike regular merge, squash merge does NOT auto-commit. You must run git commit after.
Pros: clean main history, easy to revert entire feature with one commit.
Cons: loses granular history of HOW the feature was built.
# Feature branch with 15 messy commits
git log --oneline feature
# fix typo, add tests, debug, remove debug, WIP, final version...
# Squash merge: all 15 commits become ONE
git checkout main
git merge --squash feature
# Squash commit — not a real merge, changes are staged
git status
# Changes to be committed: (all feature changes combined)
git commit -m "feat: add complete authentication module"
# One clean commit. No trace of the 15 messy commits.
# Compare histories:
# Regular merge: main gets 1 merge commit + 15 feature commits visible
# Rebase: main gets 15 clean commits in a line
# Squash: main gets 1 single commit representing everythingMerge: Use on shared/long-lived branches (main, develop) where history matters and safety is priority.
Rebase: Use on your LOCAL feature branch before pushing — clean up WIP commits, stay updated with main.
Squash merge: Use when merging a feature with messy WIP commits into main — keeps main clean.
Common team strategies:
- "Merge only": preserves everything, simple, safe. No rebase ever. (Git Flow teams)
- "Rebase + Squash": rebase local, squash-merge to main. Clean main, easy to revert. (Trunk-based teams)
- "Rebase only": full linear history, requires team discipline, dangerous if done wrong.
NEVER: rebase main, rebase shared branches, rebase after PR approval.
# Strategy 1: Merge Only (safe, simple)
git checkout main
git merge --no-ff feature # preserve all history
# Strategy 2: Rebase + Squash (clean main)
git checkout feature
git rebase main # clean up feature locally
git checkout main
git merge --squash feature # one commit on main
# Strategy 3: Rebase Only (full linear)
git checkout feature
git rebase main # linear feature
git checkout main
git merge feature # fast-forward merge (since rebased)
# OR: git rebase feature main (advanced, be careful)
# Strategy 4: GitHub's default (Squash and Merge button)
# Pull Request → Squash and Merge
# Same as: git merge --squash
Lo kar liya — Key Points:
- ✅ git merge creates a merge commit with two parents — preserves complete branch history exactly as it happened
- ✅ git rebase replays commits on top of another branch — creates linear history with no merge commits
- ✅ Rebase REWRITES history — old commits are destroyed and new ones are created with new SHA hashes
- ✅ The Golden Rule of Rebase: NEVER rebase commits that have been pushed to a shared branch
- ✅ git merge --squash combines all feature commits into one new commit — good for cleaning up WIP history
- ✅ Merge is safe and preserves truth; Rebase is clean and preserves readability
- ✅ Most modern teams: rebase local feature branches, squash-merge into main for clean history
Want to track your progress?
Log in to save your place and pick up where you left off.
Progress track karna chahte ho?
Login karo apni progress save karne ke liye aur jahan chhoda tha wahan se shuru karo.
Login