Rebase vs merge, decided in one sentence: use merge when the branch is shared with anyone else, use rebase when it's still yours alone, and stop treating this as a personality question. Both commands solve the same problem — getting one branch's commits into another — and both are correct tools that produce different, inspectable results: a different commit graph, a different diff for your reviewer, a different trail for git blame and git bisect to walk later. This guide is the comparison the other two aren't: it won't re-teach you the step-by-step mechanics of either command — those guides already do that in full — it will tell you, plainly, which one wins in which situation and why the wrong choice on a shared branch is the one Git mistake that can't be quietly walked back.

If you need the mechanics — how to actually run git rebase main, resolve a rebase conflict, or use git rebase --onto for a stacked branch — the dedicated rebase guide covers it start to finish. If you need the merge equivalent — fetching, checking out, merging, and reading a merge conflict — the merge guide does the same. For the exhaustive flag-by-flag reference behind both, Git's own git-rebase documentation and git-merge documentation are the authoritative source. This page assumes you can already run either command and answers a narrower, more useful question: given a specific situation, which one should you actually reach for?

The Fast Answer: Rebase vs Merge in One Table

Git merge vs git rebase comes down to one question: has anyone else already pulled this branch? If yes, merge. If no — it's still local, still unpushed, or pushed only to a pull request nobody else has based work on — rebase is safe and usually produces a cleaner result. That single check resolves most rebase vs merge arguments before they start.

  • Use merge when bringing an already-shared branch (main, develop, a release branch) into your work, or when integrating a finished feature branch that others may have built on top of.
  • Use rebase when cleaning up your own, still-private branch before opening a pull request, or when keeping a personal feature branch current with main as it moves.
  • Use squash merge when you want one branch's entire history to land as a single, tidy commit on main regardless of how messy the branch itself was — most teams' actual default, covered in full further down.

Everything past this point is detail in service of that one decision: what each command actually changes, what it costs you, and where rebasing vs merging git history quietly shows up later in places you don't expect — a reviewer's screen, a git blame result, a bisect run six months from now.

What Each Command Actually Does to Your Commit History

Strip away the tutorials and both commands answer the same question — "how do I get feature's commits into main?" — with genuinely different mechanics. Merge creates a new commit with two parents: the tip of the branch you're on, and the tip of the branch you're merging in. Every existing commit on both branches stays exactly as it was, hash and all; merge only ever adds, never rewrites. Rebase replays commits instead — it takes each commit unique to your branch, one at a time, and reapplies it on top of a new base, which means every replayed commit gets a brand-new hash even though its content is identical. Nothing is deleted in either case; the two operations just leave a differently shaped record of how the work happened.

# Merge: adds one new two-parent commit, rewrites nothing
git checkout feature
git merge main
# feature now has a merge commit; every prior commit hash is untouched

# Rebase: replays feature's commits onto main's tip, new hashes
git checkout feature
git rebase main
# feature's commits are gone by their old hashes, replaced by new ones with identical content

That difference in mechanism is the entire reason a rebase and merge produce different histories from identical starting points and identical final code. The files on disk can end up byte-for-byte identical either way — the git rebase vs merge choice doesn't change what the code looks like at the tip of the branch, only the paper trail describing how it got there.

Two commit graphs side by side: merge adds a new two-parent commit M joining main's tip B and feature's tip D, leaving A through D untouched; rebase instead replays feature's commits C and D directly onto main's tip B as C-prime and D-prime, each with a brand-new hash Merge Adds One Commit; Rebase Replays Every Commit MERGE — new two-parent commit main A B feature C D M 2 parents A through D all remain, untouched REBASE — replayed onto main's tip A B C' D' 9f1a2b3 7c4d5e6 C' and D' — same diffs, brand-new hashes Merge preserves both lines; rebase rewrites feature onto main's tip
Merge creates one new two-parent commit M and leaves A through D exactly where they were; rebase detaches C and D and replays them as C' and D' directly on top of main's tip, each with a new hash.

The Core Difference Between Merge and Rebase: History Shape

The difference between merge and rebase, reduced to a shape, is a diamond versus a straight line. A repository built entirely on merges looks like a lattice when you graph it — branches split off, wander independently, and rejoin at merge commits, so the graph visibly shows every place two lines of work met. A repository built on rebasing looks like a single straight rope: every commit sits directly on top of the one before it, in the order it was replayed, with no merge commits marking where a branch used to exist at all.

Neither shape is objectively better — they optimize for different things. The lattice preserves an honest record of when parallel work actually happened, which is valuable for audits, for understanding what shipped together, and for a compliance reviewer asking "what was on main on this exact date." The rope optimizes for readability after the fact: git log on a rebased history reads like a clean, ordered story with no branching noise, which is exactly why so many teams rebase feature branches before merging them — they want the honesty of merge for the integration point and the readability of rebase for everything leading up to it.

Two contrasting commit graphs: merge history is a lattice where branches diverge and rejoin twice, at merge commits M1 and M2, while rebased history is a single straight line of six sequential commits with no branch points at all A Diamond Versus a Straight Line MERGE HISTORY — a lattice hotfix M1 feature M2 M1 and M2 each carry two parents REBASED HISTORY — one straight line 1 2 3 4 5 6 No branch points — one commit after another Same amount of work, two very different shapes on the graph
A merge-only history graphs as a lattice, with M1 and M2 marking where hotfix and feature rejoined main; a rebase-only history graphs as a single rope with no branch points left to see.

This is also where "rebase and merge" as a phrase stops being contradictory and starts making sense: most real workflows use both, in sequence, rather than picking one forever. Rebase your own branch to clean it up, then merge — or squash-merge — the result into main. The two commands aren't rivals so much as two stages of the same pipeline, and the argument over rebase vs merge is really an argument about where to draw the line between "still mine to rewrite" and "now everyone's, and frozen."

Rebase vs Merge: The Full Comparison Table

Git merge vs git rebase stops being a two-way comparison the moment you open a hosting platform's merge dialog, because squash merge is right there beside the other two — and it behaves differently enough from a plain merge to deserve its own column here rather than a footnote.

Dimension Merge Rebase Squash Merge
Rewrites existing commits? Never Yes — every replayed commit gets a new hash No, but originals are collapsed into one new commit
History shape Branching, with merge commits marking join points Linear — looks like one continuous line of work Linear — one commit per feature on main
Safe on a shared branch? Always No — only on branches nobody else has pulled Yes, applied at the integration point, not to shared history
Individual commit detail preserved? Fully, plus a merge commit Fully, with new hashes, no merge commit Lost — collapsed into a single commit message
Conflict resolution style One resolution pass covering everything at once Potentially one pass per replayed commit Same as merge — one pass, applied at squash time
Effect on git blame Blame still points at the original author and date Blame points at the rebased commit's new hash and date Blame points at whoever performed the squash, on the squash date
Effect on git bisect May land on a broken intermediate commit mid-branch Each replayed commit should build and pass on its own Bisect lands on whole-feature commits, never mid-feature
Best for Integrating shared branches (main, develop, release branches) Cleaning up your own branch before it's reviewed or merged Landing a feature as one tidy unit, regardless of branch mess

Read that table by row, not by column, and the pattern holds: rebase and squash merge both buy cleaner history at the cost of some detail, while a plain merge buys a fully honest record at the cost of extra noise in git log. None of the three is strictly better across every row — which is the entire reason this remains a real decision instead of a settled default.

What Your Pull Request Reviewer Actually Sees

Almost nothing written about rebase vs merge covers what actually changes for the person reviewing your pull request — and it's the part that affects them daily, whether or not they ever type either command themselves. A merged branch shows up in a PR with every commit still intact, in its original order, each with its original author and timestamp — including the "fix typo," "wip," and "actually fix the thing this time" commits you made along the way, all visible in the PR's commit list even if the platform collapses the diff view into one unified comparison.

A rebased branch shows a different picture depending on when the rebase happened. Rebase before opening the PR, and the reviewer sees a clean, linear commit list from the start — no merge commits, no "merge main into feature" noise, just your work in order. Rebase during review, after comments have already landed on specific lines, and most platforms will re-anchor or drop those inline comments, because the commit hashes those comments were attached to no longer exist. That's a real, practical cost of rebasing mid-review that a "rebase is always cleaner" take skips entirely — clean history and preserved review context are sometimes in direct tension.

Two pull request commit-list mockups: the merge-based PR on the left keeps every original commit including wip and fix typo, with an inline review comment still anchored to a specific line; the rebased PR on the right shows a short clean commit list but a callout warning that comments made before a mid-review rebase are now orphaned What the Reviewer's Commit List Actually Shows Merge-based PR — 4 commits cbb1a2c wip d4e5f6a fix typo ! 9f1a2b3 actually fix this a1b2c3d add tests Comment still anchored to its original commit and line Every commit stays, warts and all Rebased PR — 2 commits f4a9c21 add tests 8b7c6d5 handle edge case ! Comments left on d4e5f6a no longer have a commit to anchor to — orphaned Clean list, but pre-rebase comments lose their anchor Rebase before opening the PR, not after comments arrive
A merge-based PR keeps every commit, mess and all, with inline comments still attached; a rebased PR reads cleaner but a rebase run mid-review orphans any comment anchored to a commit hash that no longer exists.

The practical rule that falls out of this: rebase before you open the pull request, not after comments start arriving. If a reviewer has already requested changes and you need to update main's latest into your branch mid-review, merge is usually the better move specifically because it won't disturb the comment thread anyone has already invested time in — a case where "rebase is always cleaner" is directly wrong for the audience that has to live with the result.

Conflicts: One Big Resolution vs Commit by Commit

Merge conflicts and rebase conflicts are resolved with the same conflict markers and the same instincts, but they arrive on a fundamentally different schedule. A merge presents every conflict at once, in a single pass — Git compares the two branch tips, flags every file where both sides touched the same lines, and waits for you to resolve the whole batch before you can commit. One resolution session, however many files are involved.

A rebase can conflict repeatedly, once per replayed commit. Because rebase reapplies commits one at a time, it's entirely possible to resolve a conflict on commit three of seven, run git rebase --continue, and immediately hit a second, unrelated conflict on commit five — each one scoped to that specific commit's changes rather than the branch's total diff. That can feel slower for a long-lived branch with many commits, but it also isolates each conflict to a smaller, more understandable unit of change, which is frequently easier to reason about than one large merge conflict spanning a branch's entire divergence.

Two flowcharts contrasting conflict timing: a merge flowchart with one conflict step covering the entire branch diff followed by a single resolve-and-commit step, next to a rebase flowchart that loops through replay commit, check for conflict, resolve, and continue, once per commit, with an arrow looping back to repeat for each remaining commit One Resolution Pass Versus One Per Commit MERGE — one pass for everything git merge main Conflict across the whole branch diff Resolve every file, stage the whole set git commit REBASE — one pass per commit Replay commit 1 Conflict? Resolve it --continue Replay commit 2 Conflict? Resolve it ...repeats per remaining commit
A merge asks you to resolve every conflicting file once, in one sitting; a rebase can loop — replay a commit, hit a conflict, resolve it, continue, and repeat — once per commit until the last one lands.

One detail trips up almost everyone who's only ever resolved merge conflicts: rebase inverts which side is "ours" and which is "theirs." In a merge, "ours" is your current branch and "theirs" is the branch coming in. In a rebase, Git is technically replaying your commits onto the target, so "ours" is the branch you're rebasing onto and "theirs" is the commit currently being replayed — backward from what merge conflict habits teach you to expect, and worth double-checking with git status rather than assuming. If a rebase turns into more conflict than it's worth, git rebase --abort reverts everything to before you started, no different in spirit from how aborting a merge undoes an in-progress merge cleanly.

The Golden Rule: Never Rebase a Shared Branch

Never rebase a branch that anyone else has already pulled. Every other git rebase vs merge trade-off in this guide is a judgement call; this one isn't, and it's the answer to almost every "is rebase dangerous" question that actually deserves a firm yes. Atlassian's merging vs rebasing tutorial states the same thing as the golden rule of rebasing, and it's the one point every credible guide on the subject agrees on.

Here's precisely why. Rebasing gives every replayed commit a new hash. If a teammate already pulled the old commits before you rebased, their local branch and your newly rebased branch now share no common history for those commits at all — as far as Git is concerned, they're unrelated commits that happen to contain similar changes. Pushing your rebased branch gets rejected as a non-fast-forward push; forcing it through with git push --force overwrites the shared branch's history on the remote, and the next time your teammate pulls, their local commits look like they diverged from a history that no longer exists upstream. Their unpushed work isn't gone — it typically survives in their local git reflog — but reconciling it is a genuinely painful, manual, and avoidable mess that a plain merge would never have caused.

The safer variant, git push --force-with-lease, at least refuses to overwrite the remote if someone else has pushed to it since you last fetched — worth using by default over a bare --force even on branches you're confident are still yours alone. But the real fix is upstream of that flag entirely: know whether a branch is shared before you touch its history. If it's only ever lived on your machine, or it's a pull request branch you're certain nobody has based work on top of, rebase freely. If it's main, develop, a release branch, or anything a second person might have already fetched, merge — and if you need to walk back a change that's already landed there, revert the merge commit instead of trying to rewrite history that isn't yours alone to rewrite.

Squash Merge: The Third Option in Every Merge Button

Every major hosting platform's merge button actually offers three choices, and the third one is the one most rebase-vs-merge writeups mention last, if at all, despite being the default plenty of teams actually pick: squash merge. It takes every commit on a branch — however many, however messy — and collapses them into exactly one new commit on the target branch, with one message you write at merge time.

Squash merge borrows something from each of the other two options. Like rebase, it produces a clean, linear result on the target branch — no merge commit, no branching noise, just one entry in git log per feature. Like merge, it doesn't touch the source branch's own commit history at all until the branch is deleted, so it's just as safe to run against a shared branch as a normal merge is. The trade-off is what it discards: every individual commit message, timestamp, and author detail from the branch collapses into that single new commit, which is exactly why a branch with commits worth preserving individually — say, a sequence someone might want to cherry-pick piece by piece later — is a poor candidate for squashing.

If you already know you want one clean commit and you're doing the cleanup yourself before merging, rather than relying on the platform's button, the dedicated guide to squashing commits with interactive rebase covers exactly that — the same collapsing effect, performed manually, with full control over the resulting commit message before it ever reaches a PR.

How Each Choice Affects git blame, git bisect and git log

Rebase vs merge stops being an abstract style preference the first time someone runs git blame on a line you touched, or git bisect lands on a commit from your branch while hunting a regression. Both tools read the exact history your integration choice created, which means the choice you made weeks or months ago is still shaping someone else's debugging session today.

git blame attributes a line to whichever commit last touched it, using that commit's recorded author and date. After a plain merge, blame still points at your original commit — same author, same original timestamp, exactly as it was written. After a rebase, blame points at the replayed commit's new hash; the author is preserved, but the commit date generally reflects when the rebase happened, not when the change was originally written, which can make a line look more recently touched than it really was. After a squash merge, blame collapses everything down to whoever performed the squash and whatever date that landed — the most information loss of the three, by a wide margin, for anyone trying to trace a specific line back to its original author and reasoning.

git bisect cares less about who touched a line and more about whether every commit it might land on actually builds and passes tests on its own. A merge-heavy history can leave bisect stuck on an intermediate commit from deep inside someone's feature branch — one that never had to build cleanly by itself, because it was always going to be combined with the rest of the branch before anyone ran it standalone. A rebased or squash-merged history tends to bisect more cleanly for exactly the opposite reason: rebase encourages each replayed commit to stand on its own, and squash guarantees bisect only ever lands on a complete, self-contained feature, never a half-finished intermediate step.

A vertical git blame panel showing the same line attributed three ways: after a merge, blame shows the original commit with alice as author and the original date; after a rebase, blame shows a new hash with alice still as author but a shifted date; after a squash, blame shows a new hash attributed to bob, who performed the squash, on the squash date. Next to it, a bisect timeline of six commits with one intermediate commit marked broken, reachable only through merge history The Same Line, Three Different Blame Results GIT BLAME ON THE SAME LINE After a merge a1b2c3d alice Mar 3 After a rebase f4a9c21 alice Aug 12* *shifted to rebase date, author kept After a squash 9c8d7e6 bob Aug 20 bob ran the squash — original author lost Merge keeps the truth; squash loses the most BISECT TIMELINE — merge history stuck here ! good bad Broken commit only existed mid-branch — never had to build standalone Rebase and squash avoid this by design Both tools read the history your integration choice left behind
Blame after a merge keeps the original author and date; after a rebase, the date shifts to the replay; after a squash, both hash and author change to whoever ran it. A merge-heavy history can also leave bisect stuck on a commit that was never meant to stand alone.

None of this makes merge "wrong" for archaeology or rebase "wrong" for bisecting — it means the choice has a second audience beyond the person making it: everyone who runs git log --grep, git blame, or git bisect against that history afterward, sometimes years later, with no memory of which integration strategy produced it.

Merge vs Rebase on GitHub, GitLab and Bitbucket

Merge vs rebase GitHub, in practice, is a per-repository setting rather than a universal default. GitHub's pull request merge button offers three explicit options — "Create a merge commit," "Squash and merge," and "Rebase and merge" — and a repository admin can disable any of them under branch settings, which is how plenty of teams enforce "always squash" or "never rebase-merge" without relying on every contributor remembering the policy. A merge vs rebase GitHub debate therefore tends to end on the repository settings page rather than in a chat thread — whoever configures the options decides what every other contributor ever sees.

GitLab's merge request widget offers merge commit and fast-forward merge as the main methods, with squash available as a checkbox option on merge commits — different in structure from GitHub's three distinct buttons. Bitbucket's pull request merge dialog presents its own three-way choice — merge commit, squash, or fast-forward — with the specific option set configurable per repository by an admin, same as the other two platforms.

The practical upshot across all three: "rebase and merge" as a button label does something slightly different from running git rebase yourself on the command line, even though it uses the same underlying mechanism. The platform rebases your PR's commits onto the target branch's current tip and fast-forwards the target to include them — no merge commit gets created, and the commits keep their individual messages, but you never see or resolve the rebase locally unless a conflict forces the platform to ask you to. Functionally it's the same linear-history outcome as a manual rebase followed by a fast-forward merge; the platform just does both steps for you behind one button.

Three simplified merge-button mockups labeled GitHub, GitLab, and Bitbucket, each structured differently: GitHub lists three separate buttons — create a merge commit, squash and merge, and rebase and merge; GitLab lists merge commit and fast-forward merge as its merge methods, with squash offered as a checkbox layered on top rather than a method of its own; Bitbucket lists merge commit, squash, and fast-forward. On all three, an admin restricts which options a repository actually exposes Overlapping Options, Three Different Menus GitHub Create a merge commit Squash and merge Rebase and merge disable any option per repo GitLab Merge commit Fast-forward merge Squash — a checkbox method set project-wide, squash per MR Bitbucket Merge commit Squash Fast-forward configurable per repo by an admin Merge, squash, rebase, fast-forward — overlapping options, different menus
GitHub exposes three separate merge buttons; GitLab picks a merge method — merge commit or fast-forward — and treats squash as a checkbox layered on top rather than a method of its own; Bitbucket offers its own three-way set. On every platform an admin decides which options a given repository actually shows.

Choosing a Team Policy (and Writing It Down)

Git rebase vs merge stops causing recurring arguments the moment a team picks a default and writes it down somewhere everyone can find it — a CONTRIBUTING file, a repository's branch protection settings, or a pinned message in the team's chat. The specific choice matters less than the fact that it's explicit and enforced, ideally by disabling the non-default options in the platform's branch settings rather than trusting everyone to remember a written rule under deadline pressure.

A policy that works for most small-to-mid teams, as a starting point rather than a mandate: rebase your own feature branch against main freely, as often as you like, right up until you open the pull request. Once it's open and under review, stop rewriting it — merge main into it if it needs updating mid-review. At integration time, squash-merge by default, reserving a plain merge commit for the rare case where a branch's individual commits are genuinely worth preserving on main — a multi-step migration, for instance, where each commit is independently meaningful and someone may need to cherry-pick just one of them later.

Whatever the policy, put a name on the exception path too: what happens when someone rebases a shared branch by accident, or a squash swallows commits someone actually needed individually. Knowing that resetting to a known-good commit or recovering through git reflog are the standard fallback moves — decided in advance, not improvised during an incident — turns a rare mistake into a five-minute fix instead of a stressful afternoon.

Five Myths About Rebasing vs Merging

Rebasing vs merging Git branches attracts more confidently wrong advice than almost any other topic in version control, usually because each side of the argument overstates its case. Five claims worth retiring:

  • "Rebase loses commits." It doesn't — it rewrites their hashes, but the content survives, and the pre-rebase state remains recoverable through git reflog for as long as Git's default retention window holds, typically 30 to 90 days locally. Nothing is deleted; the risk is entirely about shared copies diverging, not content vanishing. If you've ever needed to fully remove a commit on purpose, that's a distinct, deliberate operation — not a side effect of a routine rebase.
  • "Rebase is always cleaner, so always rebase." Cleaner history and honest history are different goals, and rebase optimizes for the first at the cost of the second. A shared branch rebased mid-review can also orphan a reviewer's inline comments, as covered above — "cleaner" isn't free.
  • "Merge is always safer, so always merge." Merge is always safe with respect to rewriting history, but a repository built entirely on merges accumulates graph noise that makes git log harder to read and can leave git bisect stuck on intermediate commits that were never meant to stand alone, as covered earlier.
  • "Force-pushing after a rebase is inherently dangerous." Force-pushing your own, unshared branch is routine and low-risk — it's force-pushing a branch someone else has already pulled that causes real damage. --force-with-lease specifically guards against the shared case by refusing to overwrite unexpected remote changes.
  • "Pick one and use it for everything." The comparison table earlier in this guide exists precisely because no single choice wins on every dimension — shared-branch safety, history readability, review continuity, and blame accuracy each favor a different option depending on the situation.

If any of these come up while you're actively untangling a mistake rather than debating theory, undoing a recent commit and amending one in place are usually faster, lower-risk fixes than reaching straight for a rebase or a force-push.

Reviewing the Diff Before You Integrate

Whichever side of rebase vs merge you land on for a given branch, the step that actually catches mistakes is the same either way: look at the diff before it lands. git diff main...feature (three dots, comparing against the point where the branches diverged) shows exactly what a merge or a rebase-and-fast-forward would introduce, without touching anything — a habit worth building regardless of which integration method a team has standardized on.

Reading that output in a terminal, in raw +/- unified-diff form, works, but it puts real weight on the reader to reconstruct the change mentally — more so once a rebase has touched several commits' worth of small formatting or reordering noise alongside the actual logic change. Pasting the same before-and-after code into a side-by-side comparison instead lines the two versions up in aligned panes, with every addition and removal highlighted in place — genuinely faster to scan than a raw patch once a change runs more than a few lines, and it works identically regardless of whether the code came from a merge, a rebase, or two versions of a file you're not even tracking in Git at all.

That last point matters more than it sounds: Diff Checker, this site's free extension, isn't a Git client and doesn't touch branches or commits — it's a second, human-readable opinion on any diff, run entirely in your browser. Paste a file's before version into one pane and its after version — pulled from either side of a rebase, either side of a merge, or just two drafts you're comparing by hand — into the other, and it lines them up side by side (or in a unified view, your choice) with syntax highlighting across 17 languages, a Smart compare mode that ignores noise like reordered object keys, and a "Show Diff Only" toggle that collapses everything except the lines that actually changed. For a rebased branch specifically, where a raw git diff can be muddied by several small commits' worth of changes layered on top of each other, seeing the true before-and-after side by side is often the fastest way to confirm nothing unexpected slipped in before you merge.

None of that replaces Git's own tooling — git diff, git log -p, and a platform's PR diff view remain the source of truth for what actually changed and why. It's a complement for the moment a diff needs a second, calmer read: before a risky merge, before approving someone else's rebase, or when explaining a change to someone who doesn't read patch syntax fluently by habit. If you want to get comfortable with branches and commits in a low-stakes setting first, a hands-on Git playground lets you practice both merging and rebasing against a repository nobody actually depends on.

Frequently Asked Questions

What is the actual difference between merge and rebase?

Merge combines two branches by creating one new commit with two parents, leaving every existing commit's hash untouched. Rebase replays your branch's commits one at a time onto a new base commit, giving each replayed commit a brand-new hash even though its content is unchanged. The files at the tip of the branch can end up identical either way — the difference is entirely in the shape and honesty of the resulting history, not in the final code.

Should I use rebase or merge for my feature branch?

Rebase your own feature branch freely while it's still private and nobody else has pulled it — it keeps history linear and easy to read. Once the branch is shared, under review, or something anyone else has already fetched, switch to merge, since merge never rewrites commits and can't cause the diverged-history problem a rebase creates on shared work.

Is rebase or merge better for GitHub pull requests?

Rebase your branch before opening the pull request for a clean commit list from the start. Once the PR is open and review comments exist, prefer merging main into it instead of rebasing again — a mid-review rebase can orphan comments anchored to commit hashes that no longer exist after the rebase. At merge time, most teams default to squash merge, which discards individual commit messages but keeps main's history as one tidy commit per feature.

Does rebasing lose commits?

No — rebasing gives commits new hashes but doesn't delete their content, and the pre-rebase state typically remains recoverable through git reflog for weeks. The real risk with rebasing isn't lost content; it's that a rebased branch's new commit hashes no longer match a teammate's copy of the old ones, which causes a painful reconciliation if that branch was already shared.

Why is rebasing a shared branch considered dangerous?

Because rebasing rewrites every replayed commit's hash. If someone else already pulled the original commits, their copy and your rebased copy no longer share history for those commits at all. Pushing the rebased branch requires a force-push that overwrites the remote's history, and anyone who already had the old commits ends up with a diverged branch that takes manual work to reconcile — avoidable entirely by merging instead on any branch other people have already fetched.

What is squash merge, and how is it different from rebase?

Squash merge collapses every commit on a branch into exactly one new commit on the target branch, written at merge time — unlike rebase, which preserves each individual commit but gives it a new hash. Squash produces the same linear, noise-free result on the target branch as a rebase-and-merge would, but at the cost of losing individual commit messages and timestamps from the original branch, which matters if any of those commits were worth preserving on their own.