Both combine two branches. The difference is what the history looks like afterward — and whether you're allowed to rewrite it.
`git merge` and `git rebase` both integrate changes from one branch into another, and in most cases produce identical final file contents. What differs is the resulting commit graph. Merge adds a new "merge commit" that has two parents, faithfully recording that two branches diverged and were joined back together — the history is a true, if messier, record of what actually happened. Rebase instead takes your branch's commits and replays them one-by-one on top of the target branch's latest commit, producing a straight, linear history that looks as if you had started your branch from that latest commit all along. The commits themselves get new hashes because their parent has changed — this is the key fact that makes rebase dangerous on shared history.
A commit's hash in Git is derived partly from its parent commit's hash. When rebase changes a commit's parent (moving it to sit on top of main's latest commit instead of its original parent), the commit's own hash necessarily changes too — and every commit after it in the chain gets a new hash as a result. This is why rebasing is "rewriting history": the old commits still technically exist in Git's object database for a while, but your branch pointer now points at an entirely new set of commits with different identities. If anyone else already pulled the old commits, their local history and yours have now diverged in a way that's confusing to reconcile — this is the reason for the common rule "never rebase a branch other people have already pulled from."
Rebase isn't strictly better — it trades away information. A merge commit preserves the fact that work happened in parallel on a separate branch and exactly when it was integrated; a rebase erases that shape entirely, producing a history that reads as if everything happened in one sequential order, which wasn't literally true. For a personal feature branch you haven't shared yet, that trade is usually worth it — a clean, linear history is genuinely easier to read and bisect. But rebasing a branch that others have already pulled rewrites commits they already have, which can cause real confusion and duplicate work when they try to sync up. The safe rule most teams use: rebase your own local, unpublished commits freely; merge (or use a team-agreed pull strategy) once a branch is shared.
Explains the real difference between git merge and git rebase — a faithful two-parent merge commit versus a rewritten, linear history — using side-by-side commit graph diagrams, and covers when each is safe to use.
Use merge for integrating a shared or long-lived branch (like a feature branch others have pulled, or merging into main/develop) where preserving an accurate record of what happened and when matters, and where you can't guarantee no one else has already based work on the branch's current commits. Merge is also simply safer for beginners since it never rewrites existing commits.
Use rebase to clean up your own local, not-yet-pushed commits before opening a pull request — squashing "fix typo" commits, reordering, or simply bringing your branch up to date with the latest main without a merge commit cluttering the log. Interactive rebase (`git rebase -i`) is also the standard tool for rewriting commit messages or combining commits before sharing work, since at that point nobody else has a copy of the old commits yet.
Never rebase commits that have already been pushed to a branch other people are using, unless the whole team has explicitly agreed to and coordinated around it. If you rebase a shared branch and force-push, anyone who already pulled the old commits will have a diverged, conflicting history with yours — resolving that mess is far more disruptive than the messier-but-honest history a merge would have produced.
No — rebase replays the same file changes from each commit, just with a new parent and new hash. The actual code content is preserved (unless a conflict arises during replay, which you resolve the same way as a merge conflict). What changes is the commit's identity/hash and its position in history, not its content.
Never rebase a branch that other people have already pulled from or based their own work on. Rebasing rewrites commit history — if others already have the old commits, rebasing and force-pushing creates two divergent, conflicting histories for the same branch, which is confusing and error-prone to reconcile.
Interactive rebase opens an editable list of the commits about to be replayed, letting you reorder them, squash multiple commits into one, edit individual commit messages, or drop commits entirely before they're replayed. It's the standard tool for tidying up a messy string of "wip" or "fix typo" commits into a clean, reviewable history before opening a pull request.
A fast-forward merge happens when the target branch (e.g. main) hasn't moved since your feature branch diverged from it — Git can simply move main's pointer forward to your branch's latest commit with no merge commit needed, since there was nothing to reconcile. It only occurs when there's no divergent history to combine, which is functionally similar to what a rebase-then-merge sequence produces.
Try our Software Engineering & Cloud Studio
More calculators, simulators, and guides for this discipline.