
Git rebase vs merge comes down to one question: when you bring a feature branch and main together, what should your history look like afterward? Both commands combine the same work. Merge joins the two lines of history with a new commit. Rebase replays your commits on top of main so the history becomes one straight line.
In this guide you'll run both commands on the same feature branch, then compare the results with git log. You'll also learn how to handle conflicts calmly, and the one rule that keeps rebase from causing trouble on a team.
- Merge and rebase both combine a feature branch with main, but they leave different histories.
- Merge adds one commit with two parents and keeps every original commit unchanged.
- Rebase replays your commits on top of the latest main, creating new commit IDs and a straight line.
- Use git log --oneline --graph to see the shape each command leaves.
- Rebase your own unshared work freely; merge anything others already have.
- 0:00Intro
- 0:26What you need to follow along
- 1:08Two ways to combine the same work
- 1:52Run git merge main on your branch
- 2:41Notice merge keeps both histories
- 3:25Run git rebase main to replay
- 4:07Verify with git log graph view
- 4:50Fix rebase conflicts and other errors
- 5:35Never rebase shared commits
- 6:17Merge vs rebase in five points
- 6:49Merge preserves history; rebase makes it linear
Gather what you need to follow along
This tutorial doesn't build an app. The goal is understanding, and you'll see it directly in your own commit history. By the end, you'll have two versions of the same work: one joined by a merge commit, and one turned into a straight line by rebase.
Seeing both shapes side by side is what makes the difference click. A practice repository works best here, because you can experiment freely without putting anything important at risk. If something goes wrong, you can simply start over.
- Git is installed on your machine
- You have a Git repository to work in
- You have a feature branch with commits of its own
- You're comfortable typing commands in a terminal
Compare the two ways to combine the same work
Here's the situation most beginners face. You've been working on a feature branch, and meanwhile main has moved on without you. You need to bring the two together. Both git merge and git rebase end with your code and main's code in the same place, so the real question is which one to use.
The difference isn't the final code. It's the record of how you got there. Merge keeps everything exactly as it happened and ties the two branches together with one extra commit that has two parents. Rebase moves your work instead: it replays each of your commits on top of main, as if you had started from the newest version of main.
So the practical way to choose is to think about the history you want. Do you want a complete record of when branches split and joined, or a clean, linear sequence of commits?
- Same goal: both combine work from two branches
- Merge: joins both histories with one new commit
- Rebase: replays your commits on top of main
- Different result: the shape of the history
Run git merge main on your feature branch
Start with merge. Open your terminal inside the repository and switch to your feature branch with git switch feature. Before merging, run git branch feature-copy. This saves an untouched copy of your branch so you can rebase the exact same commits later and compare the two results fairly.
Then run git merge main. This pulls everything new on main into your branch without changing any of your existing commits. Git may open your editor and suggest a message such as "Merge branch main". Save and close the editor, and Git creates the merge commit. With one command, both branches are combined.
- You're on the feature branch before merging
- feature-copy exists as a backup for the rebase step
- If an editor opens, save and close it to finish the merge
git switch feature
# keep a copy to try rebase later
git branch feature-copy
git merge main
Inspect what merge did to your history
Merge didn't rewrite anything. It simply added one new commit that ties the two lines of work together. Every commit you made earlier still has its original ID, date and message. Both the main branch and the feature branch flow into that merge commit, and it remembers both parents.
The result is a full history. You can still see exactly when the branches split and when they joined again. That honesty is merge's biggest strength, and it's also why merge is safe for teams: because old commits never change, teammates who already have them won't hit surprises when they pull.
The trade-off is readability. On an active project, lots of merge commits add extra entries and crossing lines to the graph, which can make the history harder to follow. Merge is honest and safe, but not always tidy.
- Your original commits keep their IDs, dates and messages
- One new merge commit has two parents
- Shared commits stay unchanged, so teammates aren't affected
- Many merges can make the graph busier
Run git rebase main to replay your commits
Now try the other approach on the copy you saved. Run git switch feature-copy to move to the untouched branch, then run git rebase main. Instead of joining two lines, rebase lifts your work up and sets it down at the tip of main, so your feature commits now sit on top of it.
Under the hood, Git sets your commits aside, moves to the latest commit on main, then reapplies each of your changes one by one in their original order. The changes look the same, but they are brand-new commits with new IDs. That's why people say rebase rewrites history, and it matters a lot once other people share those commits.
- You're on feature-copy, not the merged branch
- Your commits are reapplied in their original order
- The changes are the same, but the commit IDs are new
git switch feature-copy
git rebase main
# feature commits now sit on top of main
Verify the result with git log --graph
You've run both commands, so check what each one left behind. The command git log --oneline --graph draws your history as a small graph right in the terminal, one commit per line. Run it once on feature and once on feature-copy, and compare the shape of the lines.
On feature, the merged branch, you'll see two lines that split apart and rejoin at the merge commit, with a small fork drawn in the graph. On feature-copy, the rebased branch, the history is one straight line: your feature commits sit directly on top of the latest main commit, with no merge commit. If you see that, it worked.
- Merged branch: two lines that split and rejoin at one commit
- Rebased branch: a straight, linear history
- No merge commit appears on the rebased branch
git log --oneline --graph
# after rebase: one straight line
* Feature commit 2
* Feature commit 1
* Latest main commit
Fix rebase conflicts and other common errors
Things don't always go smoothly. The most common snag is a conflict, which happens when both branches changed the same lines. A conflict isn't a broken repository. Git simply pauses and asks you which version of those lines to keep.
Open the conflicted files and look for the markers. The competing versions appear between lines starting with <<<<<<< and >>>>>>>. Keep the code you want, delete the marker lines, and save the file. During a rebase, git add the fixed files and run git rebase --continue. If the rebase feels too messy, git rebase --abort restores your branch to how it was.
Merge conflicts follow the same calm pattern: fix the files, add them, then commit. One more error you may see is a rejected push after a rebase, because the commit IDs changed. Only force-push branches that nobody else is using.
- Rebase conflict: fix files, git add, git rebase --continue
- Want out: git rebase --abort undoes the rebase
- Merge conflict: fix files, git add, then commit
- Push rejected after rebase: force-push only unshared branches
Decide when to rebase and when to merge
One rule keeps you out of real trouble: never rebase commits others already share. Because rebase creates new commits, rebasing a shared branch leaves teammates' machines holding the old commit IDs while yours has new IDs for the same changes. The classic symptom is teammates suddenly seeing duplicate commits.
The habit that follows is simple. Rebase private work: on a branch only you've touched, rebasing onto main gives you a clean, straight history before you open a pull request. Merge shared work: once teammates have pulled your commits, use merge so their copies stay valid. This one rule prevents most rebase pain.
- Has anyone else pulled these commits? If yes, merge
- Is the branch only on your machine? Rebasing is fine
- Tidy private commits before you share them
Key takeaways
- Merge adds one joining commit and keeps both histories intact.
- Rebase replays your commits on top of main, giving a straight line with new commit IDs.
- git log --oneline --graph shows the shape each command leaves.
- For conflicts: fix the files, git add them, then continue.
- Never rebase commits others already share; merge them instead.
Frequently asked questions
What is the main difference between git rebase and git merge?
Both combine work from two branches, but they leave different histories. Merge adds a commit with two parents and keeps every original commit unchanged. Rebase replays your commits on top of main, producing a straight line with new commit IDs.
Does git rebase change my commits?
Yes. The changes in each commit stay the same, but rebase creates brand-new commits with new IDs. That's why rebasing commits other people already have can cause duplicate commits on their machines.
When should I use rebase instead of merge?
Rebase is a good fit for private work on a branch only you've touched, for example to get a clean, straight history before opening a pull request. Once teammates have pulled your commits, use merge instead.
How do I fix a conflict during a rebase?
Open the conflicted files, keep the code you want, and delete the lines between and including the <<<<<<< and >>>>>>> markers. Then git add the files and run git rebase --continue.
How do I undo a rebase that went wrong?
If the rebase is still in progress, run git rebase --abort. Git stops the rebase and restores your branch to how it was before you started.
Why was my push rejected after a rebase?
Rebase gives your commits new IDs, so they no longer match what's on the remote. Only force-push if the branch is yours alone and nobody else has pulled it.