murkshelf

Git: rebase vs merge — a practical rule of thumb

Every team argues about this. The rule that ends the argument:

Rebase commits that only you have seen. Merge commits that anyone else has already seen.

Rebase rewrites history — it takes your commits and replays them on top of a new base, creating new commits with new hashes. If a hash you rewrote exists on someone else’s machine, you now have two divergent histories and a bad afternoon. If nobody ever pulled those hashes, rewriting them costs nothing.

The daily workflow

On a feature branch, keep up to date with main:

git fetch origin
git rebase origin/main

No merge bubbles, no “Merge branch ‘main’ into feature” commits, and your diff review stays clean. When the branch is done and reviewed:

git checkout main
git merge --ff-only feature   # or push and use a PR button

The two rebes that matter

git rebase -i HEAD~5 — interactive rebase of your last five commits: squash merges a commit into the previous one, reword fixes the message, drop removes it. Run it before pushing, on commits only you have.

git rebase --onto new-base old-base branch — moves a whole range of commits from one base to another. Rare, but when you need it, nothing else works.

When you’ve already pushed

You rebased, then noticed the branch was already on the remote. If it’s truly your private branch:

git push --force-with-lease

--force-with-lease instead of --force: it refuses to overwrite the remote if someone pushed after your last fetch. That one flag has saved me at least twice.

The honest trade-off

Merge commits are not a mistake — they record “these two lines of work happened in parallel, and here is where they met”. For released branches (main, release/*) that record is worth keeping. Rebase is a history-cleaning tool for the workshop, not the warehouse.