You have a feature branch. While you worked, main moved forward. You need to bring the two together, and Git offers two ways: merge and rebase. Both end with your changes on top of the latest main. They differ in what the history looks like afterwards, and in what can go wrong.
This guide explains each one and gives a clear rule for choosing.
The Starting Point
A---B---C feature
/
D---E---F---G main
feature branched from E. Since then main gained F and G, and feature gained A, B and C.
What Git Merge Does
git switch feature
git merge main
Merge creates a new commit with two parents, which joins the two lines of work. Existing commits are not changed.
A---B---C---M feature
/ /
D---E---F---G---+ main
M is the merge commit. History shows exactly what happened: two lines of work existed, and they were joined at this point.
Strengths
- It does not rewrite history. It is safe on shared branches.
- It records when and how branches were combined.
- A conflict is resolved once, in the merge commit.
Drawbacks
- It adds merge commits, and on a busy branch the history becomes a tangle of crossing lines.
- Reading
git log --graphgets harder as merges pile up.
What Git Rebase Does
git switch feature
git rebase main
Rebase takes your commits and replays them on top of the tip of main, creating new commits with new IDs.
A'--B'--C' feature
/
D---E---F---G main
A', B' and C' have the same changes as A, B and C, with different hashes, because their parent changed. The original commits are left behind, unreferenced, until Git cleans them up.
Strengths
- History is a straight line, which is easy to read and to bisect.
- No merge commits for routine updates.
- You can clean up your own commits before sharing them.
Drawbacks
- It rewrites history. If other people have the old commits, their copies no longer match.
- A conflict can appear once per replayed commit, not once in total.
- It loses the record of when you integrated upstream changes.
Side by Side
| Merge | Rebase | |
|---|---|---|
| Changes existing commits | No | Yes, creates new ones |
| History shape | Branching, with merge commits | Linear |
| Safe on a shared branch | Yes | No |
| Conflict resolution | Once | Possibly once per commit |
| Records the integration | Yes | No |
| Undo | git revert -m 1 <merge> or reset | git reflog, then reset |
The One Rule
Never rebase commits that other people have based work on.
Rebasing replaces commits. If a colleague has pulled the originals, their branch and yours now disagree about history. Pushing the rebased branch needs a force push, and others get duplicate commits and confusing conflicts when they pull.
Rebase your own local or personal branches. Merge anything that is shared, such as main.
A Practical Workflow
Many teams use both, each where it fits:
- While working on a feature branch alone, rebase onto
mainto stay current and keep your history clean.
git fetch origin
git rebase origin/main
- If you have already pushed the branch, push the rebased version safely with a lease, which refuses to overwrite commits you have not seen:
git push --force-with-lease
- When the work is ready, merge it into
mainthrough a pull request. The team usually picks one of three merge styles there:
| Style | Result on main |
|---|---|
| Merge commit | All commits plus a merge commit |
| Squash and merge | One commit for the whole branch |
| Rebase and merge | Each commit replayed linearly, no merge commit |
Squash is popular because a messy branch becomes one tidy commit. The cost is losing the individual steps.
Cleaning Up Before You Share
Interactive rebase lets you edit your own unpublished commits:
git rebase -i HEAD~4
Git opens a list of the last four commits. You can mark each one:
pickto keep itrewordto change the messagesquashorfixupto fold it into the previous commitdropto remove it
Turning wip, fix typo, fix again into one meaningful commit before opening a pull request makes review much easier.
Pulling Without a Surprise Merge Commit
By default git pull fetches and then merges, which can add a merge commit each time you pull on a branch that has diverged. To rebase your local commits on top instead:
git pull --rebase
Or set it once:
git config --global pull.rebase true
This is safe because it only rewrites your local, unpushed commits.
Resolving Conflicts
With merge, you fix the conflicts, then commit:
git merge main
# fix the files
git add .
git commit
With rebase, you fix them one commit at a time, then continue:
git rebase main
# fix the files
git add .
git rebase --continue
If it goes badly, git rebase --abort returns you to where you started.
Recovering From a Mistake
Rebase does not destroy your original commits right away. The reflog records where every branch pointed:
git reflog
git reset --hard HEAD@{5}
Find the entry from before the rebase and reset to it. Check the target first, because reset --hard discards uncommitted changes.
Which Should You Use?
| Situation | Use |
|---|---|
Updating your private feature branch with main | Rebase |
| Cleaning up commits before a pull request | Interactive rebase |
Combining a finished feature into main | Merge, or squash merge |
| Updating a branch other people also work on | Merge |
| You want an exact record of how work was integrated | Merge |
| You want a linear, easy-to-bisect history | Rebase, or squash merge |
| You are unsure | Merge. It cannot damage shared history |
Common Mistakes
- Rebasing a shared branch. It is the cause of most rebase horror stories.
- Using
git push --forceinstead of--force-with-lease. A plain force can erase a teammate's push. - Rebasing a long-lived branch with many commits and many conflicts. Merge, or squash first.
- Squashing everything out of habit. For large changes, separate commits make review and
git blamemore useful. - Panicking after a bad rebase. The reflog almost always has what you need.
Summary
Merge preserves history and is safe everywhere. Rebase produces a cleaner history and is safe only on commits that nobody else has. Rebase your own branches to keep them current and tidy, then merge into shared branches. If you follow one rule, make it this: never rebase what others have built on.
