Rebase vs merge & resolving conflicts
Your feature branch and main have both moved forward. There are two ways to bring them together, and teams argue
about them a lot. Knowing what each does to history lets you pick deliberately.
Merge: join the histories
git switch feature/gst-report
git merge main # creates a merge commit with two parents
A merge preserves exactly what happened, including when branches diverged. The history is truthful but can look like a tangle of lines on busy projects.
Rebase: replay your commits on top
git switch feature/gst-report
git fetch origin
git rebase origin/main # re-applies your commits one by one after the latest main
Rebase gives a straight, linear history, as if you had started your work from today's main. But it creates new
commits with new hashes. That is fine for your own unpublished branch, and harmful for commits others have based
work on.
| Merge | Rebase | |
|---|---|---|
| History | Real, branched | Linear, rewritten |
| New commits created | One merge commit | A new copy of each of your commits |
| Safe on shared branches | Yes | No (golden rule: don't rebase public history) |
| Conflict resolution | Once | Possibly once per replayed commit |
Interactive rebase (git rebase -i HEAD~4) lets you squash "fix typo" commits, reorder or reword them before
opening a pull request. The -i flag needs an editor, so use it in your normal terminal.
Resolving conflicts
A conflict happens when both sides changed the same lines. Git stops and marks the file:
<<<<<<< HEAD
GST_RATE = 0.18
=======
GST_RATE = Decimal("0.18")
>>>>>>> feature/gst-report
The part above ======= is the current side, below it the incoming side. Steps:
- Run
git statusto list conflicted files. - Edit each file to the correct final version and delete all the marker lines.
- Run tests.
git addthe resolved files.- Finish with
git commit(for a merge) orgit rebase --continue(for a rebase).
Changed your mind? git merge --abort or git rebase --abort returns you to the state before you started.
During a rebase, "ours" and "theirs" are swapped compared with a merge: "ours" is the branch you are rebasing onto. Read the marker labels rather than trusting memory.
Pushing after a rebase
A rebased branch no longer matches its remote copy, so a normal push is rejected. Use:
git push --force-with-lease
Unlike plain --force, it refuses if someone else pushed to the branch since you last fetched.
Common mistakes
- Rebasing
mainor any branch teammates are using. - Leaving conflict markers in the code and committing them.
- Picking one side blindly; often the right result combines both changes.
- Using
--forceinstead of--force-with-lease.
Practice
Create a repo where main and feature both edit the same line of config.py. Resolve it once with a merge,
then reset and resolve it with a rebase. Compare git log --oneline --graph --all after each.