TechEarl

git merge vs git rebase: Which Should You Use?

git merge keeps the true history and adds a merge commit; git rebase rewrites your commits onto a new base for a clean, linear log. Here is when each fits.

Ishan Karunaratne⏱️ 8 min readUpdated
Share thisCopied
git merge vs git rebase compared: when to use a merge commit and when to rebase for a linear history

Both git merge and git rebase integrate changes from one branch into another. The difference is what they do to history. git merge preserves the true history and ties the two branches together with a new merge commit. git rebase rewrites your commits so they sit on top of the other branch, producing a straight, linear history with no merge commit. The one rule that overrides everything else: never rebase commits you have already pushed and shared.

If you only remember one thing, remember that. The rest of this page explains why, and how to choose between them the rest of the time.

The core difference in one picture

Say you branched off main to build a feature, and while you worked, someone else pushed two commits to main. Your history has diverged: your branch and main share a common ancestor but have moved apart.

git merge joins them by creating a new commit with two parents:

bash
git checkout main
git merge feature

The log now has a fork and a join. The merge commit records the moment the two lines of work came back together, and every original commit keeps its real timestamp and parent.

git rebase does something different. It takes each commit on your feature branch, sets it aside, moves your branch to the tip of main, then replays your commits one by one on top:

bash
git checkout feature
git rebase main

There is no merge commit. Your commits now appear as if you had started your work from the latest main all along. The history is a single straight line.

merge vs rebase at a glance

git mergegit rebase
History shapeBranched, with a join pointLinear, straight line
Merge commitYes, one per mergeNo
Original commitsPreserved exactly (same SHAs)Rewritten (new SHAs)
When it happenedTrue chronological orderReplayed onto the new base
Safe on shared commitsYesNo, this rewrites history
Conflict handlingResolve once, in one commitResolve per replayed commit
Easy to undoYes (revert the merge commit)Harder (needs the reflog)
Best forIntegrating shared/long-lived branchesCleaning up your own local work

The takeaway from the table: merge is the honest record, rebase is the tidy story. Neither is wrong. They optimize for different things.

When to use git merge

Reach for merge when the branch has been shared, or when you want the history to record that a feature was developed in parallel.

  • The branch is public. If you or anyone else has pushed the branch and others may have based work on it, merging is the safe integration. It adds new commits and changes nothing that already exists.
  • You want an honest audit trail. A merge commit is a real event: "this feature landed here." On a team that reviews pull requests, that merge commit is a useful anchor that ties the work to the review.
  • You want easy reversibility. A bad feature merge can be undone by reverting the single merge commit. See git reset vs git revert for which undo tool fits a shared branch (hint: it is revert, not reset).

The cost is a busier graph. A repo with dozens of contributors and no rebasing develops the classic tangled, railroad-track log. For many teams that is an acceptable trade for never rewriting shared history.

When to use git rebase

Reach for rebase to clean up your own local commits before you share them, and to keep a feature branch up to date with main without littering it with merge commits.

  • Tidy your local branch before pushing. You made five "wip" commits and a typo fix. Rebasing (especially interactive rebase) lets you reorder, reword, and combine them into a clean sequence before anyone sees them. That is the topic of squashing commits with interactive rebase.
  • Keep a feature branch current. Instead of merging main into your feature repeatedly (which sprinkles merge commits through your branch), git rebase main replays your work on the latest main and keeps the branch linear.
  • You want a readable, bisectable history. A linear log is easier to read, and git bisect works cleanly on it because every commit is a real, ordered step.

The cost is that rebasing rewrites commits. Every replayed commit gets a new SHA, because its parent changed. That is harmless on commits only you have, and dangerous on commits other people already have.

The golden rule: never rebase shared commits

This is the one mistake that turns rebase from useful into destructive.

When you rebase, Git does not move your commits. It creates new commits with the same content but different SHAs, then abandons the originals. If those original commits exist only in your local repo, nobody notices. But if you already pushed them and a teammate pulled them, their repo still has the old SHAs while yours now has new ones. Your histories have silently forked, and the next push or pull turns into a mess of duplicate commits and conflicts. The first concrete symptom is usually a non-fast-forward push that Git refuses outright.

So the rule is simple:

Rebase commits that live only in your local repository. Never rebase commits you have already pushed to a shared branch.

If you have already pushed a branch and you rebase it anyway, the only way to update the remote is a force push:

bash
git push --force-with-lease

--force-with-lease is safer than a bare --force: it refuses to overwrite the remote if someone else pushed in the meantime, so you do not silently clobber a teammate's work. But even with the lease, force-pushing a branch other people work on is something you do only by agreement, never as a reflex. On a protected main it should be impossible anyway; see how to protect your main branch.

If you do rebase or reset something you wish you had not, your old commits are not gone immediately. Git keeps them in the reflog for a while, which is how you can recover lost commits with git reflog.

A safe rebase workflow

Here is the pattern I use to keep a feature branch current and clean without touching anything shared.

First, make sure I have the latest main. If you are unsure of the difference between updating your remote-tracking refs and merging them in, read git pull vs git fetch.

bash
git checkout main
git pull

Then move my feature branch onto the fresh main. A dirty working tree blocks the rebase, so if I have uncommitted changes I stash my work-in-progress first to park them out of the way:

bash
git checkout feature
git rebase main

If a conflict comes up, Git pauses on the offending commit. I fix the files, stage them, and continue. Staging with the staging area and git add is how I tell Git the conflict is resolved and the replayed commit can use my edited version:

bash
git add path/to/file
git rebase --continue

To bail out and put everything back the way it was before the rebase started:

bash
git rebase --abort

Resolving conflicts during a rebase uses the same skills as resolving them during a merge; the mechanics are covered in how to resolve merge conflicts in Git. The difference is that a rebase can ask you to resolve a conflict on each replayed commit, where a merge asks once.

So which should you use?

A practical default that works for most small teams:

  • Rebase your local feature branch to keep it current and to clean up your commits before you open a pull request. This is private work, so rewriting is safe and the result is a tidy, reviewable branch.
  • Merge the pull request into main. The merge commit marks where the feature landed and keeps shared history append-only.

That gives you a clean per-feature history and an honest integration history at the same time. It pairs naturally with a pull-request flow: read how to create a pull request for the other half, and Git workflows for teams for how merge and rebase fit into GitHub Flow, Git Flow, and trunk-based development.

If branches still feel abstract, the foundation is Git branching explained for beginners. And whenever any of this feels overwhelming, the Git for beginners hub walks through the whole picture from the start.

Neither is better in general; they solve different problems. Rebase gives you a clean, linear history and is ideal for tidying your own local commits before you share them. Merge preserves the true history and is the safe choice for integrating branches that other people already have. Many teams rebase their private feature branches and then merge the pull request.

Not exactly. Rebase creates new commits with the same content but different identifiers, then moves your branch to point at the new ones and abandons the old ones. The originals stay in the reflog for a while, so you can usually recover them. The practical effect is that the commit identifiers change, which is why rebasing shared commits causes problems.

Because rebasing rewrites commit identifiers. Once you push, other people may have copies of the original commits. If you rebase and force push, your history and theirs diverge, and the next pull produces duplicate commits and conflicts. Only rebase commits that still live solely in your own local repository.

The conflicts themselves are the same kind of thing: two changes to the same lines. The difference is timing. A merge asks you to resolve all conflicts once, in the single merge commit. A rebase replays your commits one at a time, so it can pause and ask you to resolve a conflict on each commit it replays.

Sources

Authoritative references this article was fact-checked against.

Tagsgit merge vs rebaseGitVersion Controlmergerebasebranching

Found this useful? Pass it on.

Copied

Ishan Karunaratne

Software Systems Architect · Senior Software Engineer · Engineering Leadership

Software systems architect and senior software engineer with more than two decades designing, building, and running production software, Linux systems, and DevOps infrastructure, and lately working AI into the stack. Now a CTO, though what I write here is drawn from the full arc of that work, across architecture, engineering, and operations, not any single job.

Keep reading

Related posts

Hashcat vs John the Ripper on speed, hash coverage, file formats, attack engine, and usability, with a clear decision table for when to reach for each.

Hashcat vs John the Ripper: Which Should You Use?

Hashcat or John the Ripper? They overlap but have different sweet spots. I compare them on speed, hash and file-format coverage, the attack engine, and usability, and give a straight answer for when to reach for each. Most people end up using both.