Few topics generate more opinionated debate in engineering teams than whether to merge or rebase - and most of that debate makes more sense once you understand that the two commands make a genuinely different tradeoff, not just a stylistic one.
What merge does (recap)
A merge combines two branches by creating a new commit with two parents, leaving both branches' original commits exactly as they were. History ends up non-linear - you can see exactly when and how a branch diverged and came back together - but it does mean the commit graph has forks and joins all through it.
What rebase actually does
git rebase <branch> takes your current branch's commits, temporarily removes them, and replays them one by one on top of the latest commit on the target branch - as if you'd started your work later than you actually did. The result looks like a straight, linear line of commits with no merge commit at all. The catch: replaying a commit creates a brand new commit with a new hash, even though the content is the same. The original commits still technically exist for a while, but your branch now points at entirely different ones.
Merge keeps both histories and ties them together. Rebase rewrites your commits onto a new base, producing a clean line but new commit hashes.
The golden rule
Because rebase rewrites commit hashes, it's safe only on commits nobody else has based work on yet. If you rebase a branch that someone else has already pulled, their copy and your copy now disagree about what the history is - Git will see your rewritten commits as entirely new and separate from the old ones they still have, and reconciling the two is a genuinely painful mess. Never rebase a branch that other people have already pulled from. Rebasing your own local, not-yet-pushed, not-yet-shared feature branch is completely safe.
Interactive rebase: cleaning up before you share
git rebase -i <commit> opens an editable list of your recent commits, letting you reorder them, combine several into one ("squash"), reword messages, or drop a commit entirely - all before anyone else has seen them. This is the most common legitimate everyday use of rebase: tidying up a messy sequence of "wip," "fix typo," and "actually fix it this time" commits into something coherent, right before opening a pull request.
A practical rule for choosing
| Situation | Reach for |
|---|---|
| Cleaning up your own local commits before pushing or opening a PR | Interactive rebase |
| Keeping your feature branch up to date with a fast-moving main, before it's shared | Rebase |
| Combining a finished feature branch into main | Merge |
| Anything already pushed and potentially pulled by someone else | Merge (or revert) - never rebase |