Git Merge vs Rebase — Which One Should You Use?
git merge and git rebase both integrate changes from one branch into another — but they work differently and have different trade-offs. Choosing the right one depends on whether the branch is shared, how you want history to look, and your team’s workflow. Using the wrong strategy can leave your repository history cluttered with merge commits or, worse, cause team members to lose work when a rebased branch is force-pushed. This guide explains the difference and when to use each approach.
The Difference
Merge creates a new commit that ties two branch histories together.
Rebase rewrites history by replaying your commits on top of another branch.
# Merge preserves history
A---B---C main
\
D---E feature
\
A---B---C------F main (merge commit)
# Rebase rewrites history
A---B---C main
\
D'---E' feature (new commits)With merge, the original commits D and E remain intact and a new merge commit F connects them. With rebase, commits are recreated as D’ and E’ with new hashes on top of the latest main — history becomes a straight line. This distinction has practical implications for collaboration, debugging, and code review.
When to Merge
Merging to main (shared branch)
git checkout main
git merge featureUse merge when integrating a feature branch into a shared branch like main or develop. The merge commit makes it clear when the feature was integrated and creates a visible record of the branch’s lifecycle.
Public branches
Never rebase branches that others are working on. Use merge for any branch that has been pushed and shared. Rebasing a shared branch creates divergent history that confuses everyone else’s local clones.
When to Rebase
Cleaning up local history
git checkout feature
git rebase mainBefore pushing a feature branch, rebase it onto the latest main. This keeps history linear and avoids unnecessary merge commits. The result is a clean, readable log that’s easier to bisect later.
Interactive rebase
git rebase -i HEAD~5Squash, reorder, and reword commits before pushing. This is useful for combining “fix typo” and “oops, forgot this file” commits into meaningful, standalone changes. Never do this after pushing.
The Golden Rule
Never rebase a branch that others have based work on.
If a branch has been pushed and shared, use merge. Rebasing a shared branch creates duplicate commits and breaks everyone else’s history. When a teammate pulls after you rebase a shared branch, Git gets confused because the commit hashes changed — suddenly their history diverges from the remote. The result is a confusing mess of duplicate commits that requires manual cleanup.
Example Workflow
# Start a feature
git checkout -b my-feature main
# Work, commit, work, commit
git add .
git commit -m "Add feature part 1"
git add .
git commit -m "Add feature part 2"
# Update with latest main (rebase locally)
git rebase main
# Clean up commits
git rebase -i HEAD~2
# Push (first time)
git push -u origin my-feature
# Open PR, get review, make changes
git add .
git commit -m "Fix review feedback"
git rebase -i HEAD~3 # squash fixup into proper commits
# Force push (safe here — it's your feature branch)
git push --force-with-lease
# Merge PR (use merge, not rebase, on main)
# GitHub: "Create a merge commit"Notice the pattern: rebase on your local feature branch to keep history clean, then merge into main to preserve that clean history. The --force-with-lease flag is safer than --force because it checks that your remote branch hasn’t been updated by someone else.
Resolving Conflicts
During merge
git merge feature
# CONFLICT in file.txt
# Fix conflicts
git add file.txt
git merge --continueMerge conflicts happen once — you resolve them in the merge commit. This is straightforward and safe.
During rebase
git rebase main
# CONFLICT in file.txt
# Fix conflicts
git add file.txt
git rebase --continue
# Or skip this commit
git rebase --skip
# Or abort entirely
git rebase --abortWith rebase, you might resolve the same conflict multiple times if it touches several commits. This is the biggest practical downside of rebasing — a conflict in a shared file that appears in three commits requires three separate conflict resolutions. The --abort option is your safety net: if a rebase becomes too complex, run git rebase --abort to return everything to the state before you started. There is no shame in aborting and choosing merge instead when conflicts become overwhelming.
PR Workflow Comparison
| Action | Merge | Rebase |
|---|---|---|
| Update feature branch | git merge main | git rebase main |
| History on main | Linear + merge commits | Linear only |
| Commit authorship | Preserved | Preserved (new hashes) |
| Safe for shared branches | Yes | No |
Team Policy Recommendation
For most teams, a simple policy works best: rebase before review, merge at merge time.
Before you open a pull request, rebase your feature branch onto the latest main to produce a clean, linear history. During the PR, if new commits are pushed to main (from other merged PRs), rebase again to keep your branch up to date. When the PR is approved, use a regular merge commit to integrate into main. This gives you the best of both worlds: clean feature branch history during development and explicit merge points on main that document when features were integrated.
Quick Decision Guide
| Situation | Use |
|---|---|
| Integrating a PR into main | Merge |
| Updating your local feature branch | Rebase |
| Shared branch with collaborators | Merge |
| Cleaning commits before push | Rebase (interactive) |
| Branch that has been pushed | Merge |
| Branch you haven’t pushed yet | Rebase |
Merge Strategies in Depth
Git supports several merge strategies beyond the default recursive merge:
# Fast-forward merge (if possible)
git merge --ff feature
# No fast-forward (always creates a merge commit)
git merge --no-ff feature
# Squash merge (flatten all feature commits into one)
git merge --squash feature
git commit -m "Add feature X"The --no-ff flag is common in Git Flow workflows where every feature branch merge should produce a visible merge commit. The --squash flag is useful when you want to collapse a messy feature branch history into a single clean commit on main.
Visual Merge vs Rebase in Practice
One way to understand the difference is to look at git log --graph output after each operation:
After merge:
* a1b2c3d (HEAD -> main) Merge branch 'feature/login'
|\
| * e4f5g6d (feature/login) Add login form validation
| * i7j8k9d Implement OAuth provider
|/
* m0n1o2d Setup project structureAfter rebase:
* a1b2c3d (HEAD -> main) Add login form validation
* e4f5g6d Implement OAuth provider
* i7j8k9d (feature/login) Setup project structureThe rebase history is linear and easier to read at a glance, but you lose the information that those commits were developed together on a feature branch. The choice often comes down to whether you value a clean linear history or a detailed record of branch structure.
Common Rebase Mistakes
- Rebasing a shared branch — The cardinal sin. Always check if anyone else has pulled your branch before rebasing.
- Force pushing after rebase — Always use
--force-with-leaseinstead of--force. The lease variant checks that your remote branch hasn’t been updated, preventing accidental overwrites of others’ work. - Rebasing main onto feature — This reverses the direction and rewrites main’s history. Only rebase feature onto main.
- Not aborting a conflicted rebase — If you get stuck in the middle of a complex rebase,
git rebase --abortis always an option. Don’t try to force your way through it.
Related: Learn Git branching strategies and advanced Git commands.
FAQ
Q: Does rebase change the commit author and date?
A: By default, rebase preserves the author name and email but changes the commit hash and committer date. Use --committer-date-is-author-date to preserve the original commit date.
Q: Is it safe to rebase a branch that only I work on? A: Yes — if you are the only person working on the branch, rebasing is safe and recommended to keep a clean history.
Q: What is the difference between git merge --squash and git rebase -i?
A: git merge --squash collapses all feature branch commits into one commit on merge. git rebase -i lets you selectively squash, reorder, and rewrite commits before merging.
Q: Why does rebase create new commit hashes? A: Because the commits are replayed on top of a different base. The commit hash incorporates the parent hash, so changing the parent changes the hash even if the content is identical.
Q: What does --force-with-lease protect against?
A: It prevents you from overwriting remote commits that someone else pushed after your last fetch. Regular --force would overwrite them silently. Think of it as --force with a safety check.
Q: How do I recover from a botched rebase?
A: Use git rebase --abort to cancel the rebase and return to the state before you started. If you already completed a bad rebase, use git reflog to find the previous state and git reset --hard <hash> to restore it.