DEV Community

Daniel Rusnok
Daniel Rusnok

Posted on • Originally published at levelup.gitconnected.com

I Thought I Understood Git. Then I Actually Learned the Difference Between Rebase and Merge.

Merge | Rebase graph

I used git rebase long before I actually understood what it does.

I picked it up from a senior developer on my first team. The rule was simple: always rebase before you merge, keep the history clean.

I followed it. I typed the commands. I never questioned it.

Then one day I rebased the wrong branch and rewrote a week of shared history. That was the day I finally sat down and learned what I had been doing.


What merge actually does

git merge takes two branches and joins them. It creates a new commit — a merge commit — that has two parents: the tip of your branch and the tip of the branch you're merging into.

# You're on feature/my-feature
git merge main
Enter fullscreen mode Exit fullscreen mode

The result is a non-destructive operation. Nothing is rewritten. Your history grows a new node with two parents, and both lines of development are preserved exactly as they happened.

      A---B---C  feature
     /         \
D---E---F---G---H  main (merge commit)
Enter fullscreen mode Exit fullscreen mode

The upside — it's safe.

The downside — if you merge large feature branches frequently, the commit history can become harder to read.


What rebase actually does

git rebase moves your commits. It takes the commits on your branch and replays them on top of another branch, one by one, as if you had started your work from there.

# You're on feature/my-feature
git rebase main
Enter fullscreen mode Exit fullscreen mode
# Before
      A---B---C  feature
     /
D---E---F---G  main

# After
              A'--B'--C'  feature
             /
D---E---F---G  main
Enter fullscreen mode Exit fullscreen mode

Notice the prime marks — A', B', C' are new commits. Same changes, new hashes. Rebase rewrites history.

The upside — your history looks linear and clean.

The downside — if anyone else has those original commits (A, B, C), their history now diverges from yours. This is what I did wrong.


The golden rule of rebase

Never rebase commits that exist outside your local repository.

If you've pushed a branch and someone else has pulled it, rebasing rewrites commits they already have. Their history diverges. Pulling becomes painful. You'll see duplicate commits, conflicts that make no sense, and a very confused colleague.

The safe version — rebase only your local, unpushed work. Once commits are shared, merge.

# ✅ Safe — rebasing local work before pushing
git rebase main
git push origin feature/my-feature

# ❌ Dangerous — rebasing already-pushed commits
git push origin feature/my-feature  # already done
git rebase main                      # rewrites shared history
git push --force                     # now you've broken everyone else
Enter fullscreen mode Exit fullscreen mode

Interactive rebase

Once you understand what rebase does, git rebase -i becomes one of the most useful tools in Git.

It lets you rewrite your local commit history before you share it — squash messy WIP commits into clean ones, reorder commits, edit commit messages, or split a large commit into smaller ones.

# Rewrite the last 3 commits interactively
git rebase -i HEAD~3
Enter fullscreen mode Exit fullscreen mode

This opens an editor where you choose what to do with each commit:

pick a1b2c3 Add order validation
pick d4e5f6 fix typo
pick g7h8i9 WIP: still debugging

# Change to:
pick a1b2c3 Add order validation
squash d4e5f6 fix typo
drop g7h8i9 WIP: still debugging
Enter fullscreen mode Exit fullscreen mode

The result — one clean commit instead of three messy ones.

This is what "clean history" actually means in practice — not avoiding merge commits, but being intentional about what you leave behind.


When to use which

Use merge when:

  • Integrating a completed feature branch into main or develop
  • Working on a shared branch where others have the same commits
  • You want to preserve the full context of when and how branches diverged
  • Merging release branches or hotfixes where an audit trail matters

Use rebase when:

  • Updating your local feature branch with changes from main before pushing
  • Cleaning up local commit history before opening a PR (with -i)
  • Keeping a long-lived feature branch up to date with the base branch
  • Working solo on a branch nobody else has touched

Never rebase:

  • Commits that have already been pushed and shared
  • main, develop, or any branch others are working from

The workflow that actually works

In practice, most teams land somewhere between "always merge" and "always rebase." Here's a workflow that's served me well:

  1. Work locally on a feature branch
  2. Before opening a PR, git rebase -i to clean up commits
  3. git rebase main to update your branch with latest changes
  4. Push and open the PR
  5. Merge the PR into main (with a merge commit or squash merge — team's call)

This gives you a clean PR history while preserving the merge commit that marks when a feature landed in main. Best of both approaches.


What I wish I had understood earlier

Rebase and merge aren't competing philosophies. They're different tools for different moments in a workflow.

Merge preserves history. Rebase rewrites it. Both are useful — but rewriting shared history is always a mistake.

I learned that the hard way. The senior developer who taught me to "always rebase" wasn't wrong — he just assumed I understood what rebase does. I didn't. I copied the command without understanding the consequence.

Now I understand both. And I still rebase — just never the wrong branch.


How does your team handle this? Do you have a strict rebase-only policy, or do you let developers decide? I'm curious whether the "clean history" argument is still winning in 2026. 👇

Top comments (0)