Chapter 5.2 — Rebase onto Main☕ 18 min read

Rebase Onto Main

Roz ka rebase = roz ka chota conflict. Mahine baad ka merge = ek bada aafat.

01The Setup

Your feature branch was created from main 2 weeks ago. Since then, main has 50 new commits. Your branch is way behind.

If you try to merge your feature now, you will get a MASSIVE merge conflict — 2 weeks of divergence compressed into one painful resolution session.

Solution: git rebase origin/main — replay your commits ON TOP of the latest main. Instead of one giant conflict, you resolve conflicts incrementally, one commit at a time.

Benefits of rebasing onto main:

  • Incremental conflict resolution — resolve one commit at a time instead of all at once
  • Keeps your branch updated — always working with the latest code
  • Clean final merge — when feature is ready, merging into main is a fast-forward
  • Easier code review — clean, linear history is simpler to review

Rule of thumb: rebase daily on long-lived feature branches. The longer you wait, the worse the conflicts.

# Problem: feature is 2 weeks behind main
git log --oneline feature..origin/main
# 50 commits on main that you don't have!

# Solution: rebase onto latest main
git checkout feature
git rebase origin/main
# Git replays YOUR commits on top of latest main
# Conflicts are resolved per-commit (smaller, easier)

# Result: feature is now AHEAD of main with all changes
git merge feature  # on main: fast-forward, no conflict!
02Fetch First

What actually happens when you run git rebase origin/main? Let us break it down step by step.

Step 1: Git finds the common ancestor between your branch and the target (origin/main).

Step 2: Git saves your commits temporarily — it creates patch files for each commit that exists on your branch but not on the target.

Step 3: Git resets your branch to match the target exactly. Your branch now looks identical to origin/main — all your commits are gone (temporarily!).

Step 4: Git re-applies your saved commits one by one on top of the new base. Each commit is applied as if you just wrote it fresh.

Each re-applied commit gets a NEW SHA hash because its parent has changed. This is why rebase "rewrites history" — the commits are recreated, not moved.

If a commit conflicts during re-application, Git pauses and asks you to resolve before continuing. This is the incremental conflict resolution that makes rebase so powerful.

# Step-by-step rebase visualization
# Before:  A --- B --- C (main)
#           \
#            D --- E (feature, branched from A)

git checkout feature
git rebase main

# Step 1: Find common ancestor = A
# Step 2: Save D and E as patches
# Step 3: Reset feature to match main (A-B-C)
# Step 4: Apply D then E on top of C

# After:   A --- B --- C (main)
#                    \
#                     D' --- E' (feature, now based on C)
# D and E get new hashes D' and E' because parent changed
💡 Pro Tip: Think of rebase like reorganizing a stack of plates. You take your plates (commits) off the table, put a new tablecloth (latest main) down, then put your plates back on top one by one. Same plates, same order, but on a new base.
03Rebase onto Main

After rebase, your local branch has NEW commit hashes. The remote still has the OLD hashes. This creates a problem.

git push will FAIL with the error: "Updates were rejected because the tip of your current branch is behind." Git thinks your branch diverged because the hashes do not match.

You MUST force push: git push --force-with-lease origin feature

Two options for force pushing:

  • --force = overwrite remote without checking. DANGEROUS — can delete teammates' commits silently.
  • --force-with-lease = overwrite ONLY if no one else pushed new commits. SAFE.

Always use --force-with-lease. Make it an alias so you never forget:

git checkout feature
git rebase origin/main
# Success! Commits are replayed.

# Normal push fails
git push origin feature
# ERROR: Updates were rejected because the remote contains work that you do
# not have locally.

# Safe force push
git push --force-with-lease origin feature
# Enumerating objects: 7, done.
# To /github.com/user/repo.git
#  + abc1234...def5678 feature -> feature (forced update)

# Why --force-with-lease is safer:
# If teammate pushed new commits while you were rebasing,
# --force-with-lease FAILS, protecting their work.
# --force would overwrite their commits silently!
04Force Push Safely

Long-lived feature branches are DANGEROUS. The longer you wait to sync with main, the worse the merge will be.

Best practice: git rebase origin/main EVERY DAY before starting work.

Daily rebase means: 0-1 small conflicts per day vs 50 massive conflicts on merge day. Which would you prefer?

The daily process is simple:

  • git fetch origin — get latest remote info
  • git rebase origin/main — replay commits on top
  • Resolve any small conflicts (usually 0-1)
  • Continue working

Alternative shortcut: git pull --rebase origin main — fetch + rebase in one command.

Even better: configure rebase as the default for pull so you never have to think about it.

# Daily workflow: stay updated with main
git fetch origin                    # get latest remote info
git rebase origin/main             # replay commits on top

# If conflicts:
# 1. Resolve conflict in file
# 2. git add the-resolved-file
# 3. git rebase --continue

# If no conflicts:
# Rebase is automatic. Continue coding.

# One-liner: fetch + rebase
git pull --rebase origin main

# Set rebase as default for pull
git config --global pull.rebase true
# Now git pull = git pull --rebase
# No more unnecessary merge commits from pull!
Configure git config --global pull.rebase true once and forget. Every git pull will use rebase instead of creating ugly merge commits like "Merge branch main of origin". Your history stays clean automatically. This is one of the first things senior developers configure on a new machine.
05Common Pitfalls

Both git merge origin/main and git rebase origin/main update your feature branch with main's changes. Which should you use?

Merge: creates a merge commit in your feature branch. History shows when you synced. Safe but noisy.

Rebase: replays your commits on top. Clean history. But requires force push.

Use rebase when:

  • You are the only one on the branch
  • You want clean, linear history
  • You have not pushed yet (no force push needed)

Use merge when:

  • Others are working on the same branch
  • You have already pushed and do not want to force push
  • You want to preserve the sync point in history

Neither is wrong — know the tradeoffs.

# OPTION A: Rebase (clean, but requires force push)
git checkout feature
git rebase origin/main
git push --force-with-lease origin feature

# OPTION B: Merge (safe, creates merge commit)
git checkout feature
git merge origin/main
git push origin feature  # normal push, no force needed

# OPTION C: Merge but squash main's commits (advanced)
git merge --squash origin/main
git commit -m "sync with main"
# Main's 50 commits become 1 merge commit in feature
# Keeps feature history cleaner than regular merge

Lo kar liya — Key Points:

  • ✅ git rebase origin/main replays your feature commits on top of the latest main — keeps your branch updated
  • ✅ Rebase resolves conflicts incrementally (one commit at a time) instead of one massive merge conflict
  • ✅ After rebase, commit hashes change — you MUST use git push --force-with-lease to update the remote
  • ✅ --force-with-lease is safe: it fails if someone else pushed new commits to the branch
  • ✅ --force is dangerous: it silently overwrites others' work without checking
  • ✅ Rebase daily on long-lived feature branches to prevent massive conflicts later
  • ✅ git config --global pull.rebase true makes git pull use rebase instead of creating merge commits
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase