Every team eventually has the rebase-vs-merge argument. Both commands solve the same problem — combining diverging branches — but they leave very different history behind.
What each command actually does
git merge creates a new commit that ties two branches together, preserving both histories exactly as they happened.
git checkout main
git merge feature/logingit rebase replays your branch's commits on top of another branch, rewriting commit hashes in the process.
git checkout feature/login
git rebase mainThe tradeoff in one sentence
Merge preserves true history at the cost of a messier graph; rebase produces a clean, linear graph at the cost of rewriting history.
When to merge
- Merging a feature branch into
mainvia a pull request — keep the merge commit as a record of when the feature landed. - Any branch that other people have already pulled and built on top of. Rewriting shared history breaks their local branches.
When to rebase
- Cleaning up your own local commits before opening a pull request (
git rebase -i). - Keeping a long-lived feature branch up to date with
mainwithout a "merge main into feature" commit on every sync.
git fetch origin
git rebase origin/mainThe golden rule
Never rebase a branch that others have already pulled from, unless the whole team has agreed to force-push and re-sync. Rebasing rewrites commit SHAs — anyone with the old commits will get conflicting history.
A sane default for most teams
- Rebase locally to keep your own commits clean.
- Merge (often via a "squash and merge" PR) when landing into a shared branch.
That combination gives you a readable personal workflow and a stable, non-destructive shared history.