What rebase does
Git takes every commit that is on your branch and not on main, and applies them one at a time on top of main. The changes are the same; the commits are new objects with new ids, because a commit id includes its parent.
The result is a straight line: it looks as though you started your branch this morning, from the latest main.
before after: git switch feature; git rebase main
A ── B ── C (main) A ── B ── C (main)
\ \
D ── E (feature) D' ── E' (feature)
The two ways to catch up
Merging records the truth: you branched at B and caught up later. Rebasing produces a history that is easier to read: one clean line of your commits, each of which can be reviewed and reverted on its own. Both are legitimate; teams pick one and write it down.
git switch feature
git merge main # a merge commit appears in your branch
git rebase main # your commits move on top of main instead
The one rule
The practical version: rebase a branch only you are working on, as often as you like. Once you have opened a pull request that others are reviewing, prefer merges — or warn them before you force-push.
Rebasing replaces commits with new ones. Anyone who already pulled the old ids now has commits that no longer exist in your branch, and their next pull produces duplicates or a mess. Rebase your own unpushed work freely; leave shared history alone.
When it stops
git rebase main
# CONFLICT in price-list.md
# fix the file, then
git add price-list.md
git rebase --continue
git rebase --skip # drop this commit
git rebase --abort # put everything back
During a rebase your commits are being replayed onto main, so "ours" is main and "theirs" is your own commit. Read the file, not the labels.
The pull that is really a rebase
A plain git pull that finds new commits makes a merge commit, and a busy repository fills up with "Merge branch 'main' of github.com…" noise. --rebase replays your local commits on top instead — which is almost always what you meant.
git pull --rebase # once
git config --global pull.rebase true # for good