GitRebase vs Merge

Rebase vs Merge

Merge and rebase both bring changes from one branch into another, but they do it differently — and the difference shows up in your project’s history. Most Git arguments boil down to which one a team should use. The honest answer is that both are useful; the question is which trade-offs you prefer.

What each one does

Starting point

Text
        A───B───C───F   ◀── main
                 \
                  D───E       ◀── feature

After 'git merge feature' on main

Text
        A───B───C───F───M   ◀── main
                 \         /
                  D───E───┘    ◀── feature
        ↑ M is a merge commit (two parents)

After 'git rebase main' on feature

Text
        A───B───C───F───D'───E'   ◀── feature

        D' and E' are NEW commits (same content, different hashes)
        feature now appears to have been branched from F
Side-by-side comparison

Aspect

Merge

Rebase

Creates new commits?

One (the merge commit)

Re-creates all your commits with new hashes

History shape

Diamond / graph

Linear / straight line

Preserves true timeline

Yes

No — pretends work happened sequentially

Safe to push to shared branches

Yes

Only if you’re the sole user of that branch

git log --graph readability

Shows branches explicitly

Shows nothing about the branches

Easy to revert

One commit (the merge)

N commits (one per rebased commit)

Conflict handling

Resolve once

May need to resolve per replayed commit

Required after the fact

Just push

Force-push (--force-with-lease)

When merging is the better choice
  • Shared branches — main, develop, release. Rebasing these and force-pushing breaks everyone’s local copies.

  • Wanting an honest record — “these two branches existed and met here” is a useful historical fact.

  • Auditing requirements — when compliance demands a verifiable timeline of who did what when.

  • Long-lived branches — release branches that hotfixes flow into.

  • You merged with --no-ff as a team convention.

When rebasing is the better choice
  • Updating your local feature branch with the latest main, before pushing.

  • Polishing commits before review — squashing WIP commits, fixing typos in messages.

  • Linear history is a team valuegit log is easier to scan.

  • Bisecting — linear history makes binary search for bugs much more reliable.

  • Personal experimental branches — nobody else has them, no risk.

Common workflows that combine both

Hybrid: rebase locally, merge to share

Bash
# While developing your feature branch:
git pull --rebase origin main          # bring main's changes onto your branch

# Right before opening a PR:
git rebase -i main                     # tidy up your commits

# When merging on GitHub: use "Merge commit" or "Squash and merge"
# The PR itself is a merge — but your branch is clean and linear.
The “three styles” a team typically picks
  • Always merge (with --no-ff). Detailed history, every feature visible as a diamond. Used by Gitflow.

  • Rebase locally, merge to share. Personal branches are linear; main shows one merge per feature.

  • Always squash. Each PR collapses into one commit on main. Cleanest possible log.

Decision flowchart

Text
Are these commits already pushed AND used by others?
├── YES → MERGE (don't rebase shared history)
└── NO →
    Are you trying to combine work or update a local branch?
    ├── Updating local branch → REBASE
    └── Bringing two diverged branches together
        ├── Want a clear "branch was merged here" marker → MERGE --no-ff
        ├── Want a clean linear log → REBASE then merge
        └── Don't care about commits, want one entry → SQUASH
The golden rule (worth repeating)
The single most-violated rule in Git
**Don’t rebase commits that exist outside your repository.** Once you’ve pushed a commit and someone else has it, leave it alone. Rebase only:
— Local commits not yet pushed.
— Branches that are explicitly “mine alone” (most feature branches on solo work).
Both are equally valid

There are healthy teams running every possible strategy. Linux uses merge. Many startups use squash. Plenty of mid- size teams rebase. The mistake is mixing styles inconsistently within the same repo — that produces confusing histories. Pick one, document it in CONTRIBUTING.md, and trust it.

Tip
For most teams, the right answer is: rebase your branch onto main before opening a PR; merge the PR on GitHub. Your branch stays clean and linear; main gets a clear merge per feature.