Git Merge vs Rebase: When to Use Each
A clear comparison of git merge and git rebase — what each one does to history, the trade-offs, the golden rule, and a practical decision guide for beginners.
What you'll learn
- ✓What git merge and git rebase each do to the commit graph
- ✓Why "rebase rewrites history" is the key idea
- ✓The golden rule of rebasing — and what happens if you break it
- ✓How to integrate the latest main into your feature branch safely
- ✓A practical decision guide for choosing between the two
Prerequisites
- •Comfortable creating and merging branches — see Git Branching
- •Familiarity with git log --oneline --graph
Once you are comfortable with branches, the next question every Git learner runs into is: merge or rebase? Both incorporate one line of work into another. They do it differently, and they produce different-looking histories. Neither is universally correct. The goal of this post is to give you a clear mental model and a simple rule of thumb for choosing.
The starting situation
Both operations exist to solve the same problem. You start with this:
E---F (feature)
/
A---B---C---D (main)
You made commits E and F on a branch called feature. Meanwhile, someone added commit D to main. The two branches have diverged. You want them to come back together. There are two paths.
What git merge does
git switch main
git merge feature
If the branches have diverged (as they have here), Git creates a merge commit M whose parents are the tips of both branches:
E---F
/ \
A---B---C---D-----M (main)
History is preserved exactly as it happened: there was a line of work, there was another line of work, they came back together at M. Nothing about E or F is changed. The hashes are unchanged. Anyone else who had E and F still has the same E and F.
The cost is that the graph gets bumpy. A project with lots of merges and short branches develops a history that looks like a railway map. For some teams this is fine; for others it feels noisy.
What git rebase does
Rebase takes a different approach. From the feature branch, you run:
git switch feature
git rebase main
Git temporarily sets your commits E and F aside, fast-forwards feature to the tip of main (D), and then reapplies your commits one at a time on top:
E'---F' (feature)
/
A---B---C---D (main)
The result is a linear history: it looks as though you did your work directly on top of the latest main. There is no merge commit and no bump in the graph.
Notice the prime marks on E' and F'. They are not the same commits as E and F — they have different hashes because their parent is now D instead of C. Conceptually they are the same change, but Git treats them as new commits. This is what people mean when they say “rebase rewrites history.”
After the rebase, you can fast-forward main onto the rebased branch and end up with a perfectly straight line:
git switch main
git merge feature # this is a fast-forward
A---B---C---D---E'---F' (main, feature)
That straight line is exactly the appeal of rebase. git log --oneline reads like a clean story rather than a tangle.
The golden rule of rebasing
The single rule you must internalise:
Never rebase commits that you have already shared with other people.
Why? Because rebase rewrites commits, replacing E and F with new commits E' and F' that have different hashes. If your teammate already pulled E and F and started building on them, their copy of history is now different from yours. The next time anyone tries to combine the two, Git will see two parallel sets of commits that look like duplicates, and merging them produces a confusing mess.
In practice this means:
- Rebasing your local, unpushed commits — safe and often useful.
- Rebasing your own branch on top of
mainto keep it up to date — safe, as long as nobody else is collaborating on that branch. - Rebasing commits that are already on a shared branch like
main— almost always a bad idea.
Stick to that rule and rebase becomes a sharp tool. Break it and you create work for everyone on your team.
A common rebase use case
The most useful application of rebase for beginners is keeping your feature branch up to date with main while you work on it.
You have been working on feature for a few days. Other commits have landed on main. Before opening a pull request, you want your branch to be based on the latest main so the eventual integration is trivial.
git switch feature
git fetch origin
git rebase origin/main
git fetch downloads any new commits from the remote without changing your branches; we will cover this properly in the next post. After the rebase, feature sits cleanly on top of the latest main and the diff of your branch shows only your actual changes — not a tangle of integration noise.
If conflicts arise, Git pauses at the offending commit and tells you what to do:
CONFLICT (content): Merge conflict in app.js
error: could not apply <hash>... Your commit message
Resolve the conflict in the same way as a merge conflict (edit the file, remove the markers), then:
git add app.js
git rebase --continue
If a rebase goes badly:
git rebase --abort
…and the repository returns to exactly the state it was in before you started.
When to choose merge
Merge is the right choice when:
- The commits you are integrating have been pushed and shared with others.
- You want the history to honestly record that a branch existed and was merged.
- You are merging a long-running release or shared integration branch.
- You are working on a team that has agreed on a “merge always” policy.
Merge is also the safer default for beginners. Nothing is rewritten; nothing is lost. The worst case is a slightly noisier graph.
When to choose rebase
Rebase is the right choice when:
- You are tidying up your own local commits before sharing them.
- You want to update a feature branch with the latest
mainso the eventual merge is fast-forward. - The project values a linear history and the team has agreed on it.
- The commits being rebased are not yet pushed (or are on a branch only you touch).
Most professional teams converge on a hybrid: rebase locally to keep things clean, merge to share work into the long-lived branches.
Try it yourself. In a practice repository on main: create feature, make two commits on it. Switch back to main, make one commit there so the branches diverge. Now in one terminal try git merge feature and look at git log --oneline --graph --all. Reset (git reset --hard <hash-of-main-before-the-merge>) and try git rebase main from the feature branch instead. Compare the two graphs.
Reading the history
After either operation, the most useful single command is:
git log --oneline --graph --all --decorate
This shows you, in one screen, every branch and how they relate. After a merge you will see a diamond pattern with a merge commit. After a rebase you will see a single straight line. Get comfortable reading this output; it is how experienced Git users orient themselves.
Interactive rebase: a brief mention
Rebase has a more advanced mode worth knowing about even if you do not use it yet:
git rebase -i HEAD~5
This opens an editor listing your last five commits and lets you reorder them, combine (“squash”) them, edit their messages, or drop them entirely. It is the standard way professionals clean up a messy feature branch into a small number of well-described commits before sharing it.
The same golden rule applies: only use interactive rebase on commits that have not been pushed. Used properly, it is one of the most powerful tools Git provides.
Try it yourself. In a practice repository, make four small commits on a feature branch with deliberately unhelpful messages (“wip”, “more”, “fix”, “asdf”). Run git rebase -i HEAD~4 and use the reword action to give each commit a sensible message, and the squash action to combine two of them into one. Inspect git log afterwards.
A simple decision guide
| Situation | Use |
|---|---|
| Pulling latest changes from a shared branch | merge (or pull with merge) |
Updating your private feature branch with latest main | rebase |
| Tidying up your last few local commits | rebase -i |
Integrating a finished feature into main | either — follow team convention |
| Working on a branch with collaborators | merge |
| In doubt | merge |
When you are not sure, merge. It is safer, it is harder to break things, and the resulting history is honest. Reach for rebase when you have a specific reason — a cleaner graph for a pull request, a tidy set of commits to share, or a feature branch that needs the latest main underneath it.
What about git pull?
git pull is git fetch followed by an integration step — by default merge, but it can be configured to use rebase instead. With the configuration we set in the install post (pull.rebase = false), git pull performs a merge. That is the safe default. You can override it for a single command with git pull --rebase when you want a linear history.
Recap
You now know:
- Merge preserves history and creates a merge commit when branches have diverged.
- Rebase replays your commits on top of another branch, producing new commits with new hashes and a linear history.
- The golden rule: do not rebase commits that have been shared with others.
- The everyday use of rebase is keeping your feature branch on top of the latest
mainbefore sharing it. - When in doubt, merge is the safer choice; reach for rebase when you have a specific reason.
Next steps
The final post in this series puts everything together with a practical workflow built around Git and GitHub — cloning, pushing, pull requests, and a daily routine that works for solo developers and small teams.
→ Next: A Practical Git + GitHub Workflow for Solo Developers
Questions or feedback? Email codeloomdevv@gmail.com.