Should you rebase a fork topic branch onto upstream/main or merge upstream/main into it before review?
answer
- One rewrites, one records
- Ask who else holds these commits
- Watch what happens to commit SHAs
- Force-push versus fast-forward
- Rebase alone-owned branches, merge shared ones
basics
~20 sRebasing replays your commits on the new base and yields a clean linear series, but rewrites their SHAs so republishing to your fork needs a force-push. Merging keeps existing SHAs and adds a merge commit. Prefer rebase for branches only you push.
solid answer
~50 sBoth refresh the base; they differ in what happens to your commits. `git rebase upstream/main` replays each of your commits onto upstream's current tip, producing new commits with new SHAs and a strictly linear branch — reviewers then read your change against today's code with no unrelated merge noise. The cost is that the branch's old commits are gone, so pushing to your fork requires `git push --force-with-lease`, and anyone who already fetched those commits has to reset. `git merge upstream/main` leaves your commits untouched and records a merge commit; the push stays a fast-forward, but the branch now interleaves upstream history with yours and its diff is harder to read. My rule: rebase while the branch is mine alone, which is the normal case for a fork topic branch; switch to merging once someone else has built on it, or once the rebase conflicts have become large enough that redoing them per commit costs more than one merge resolution.
code
bash · 4 linesgit fetch upstream
git switch feature/parser
git rebase upstream/main
git push --force-with-lease origin feature/parsergo deeper
Know that both commands refresh your branch onto newer upstream code, and that rebase creates new commits while merge adds a merge commit. Recall that rebasing a pushed branch means force-pushing it.
Explain the mechanics: rebase replays commits with new SHAs and resolves conflicts per commit; merge preserves SHAs and resolves once. Tie each to whether the follow-up push is a fast-forward.
Give a decision rule and defend it — who else holds the commits, how big the conflict debt is, what reviewers have to read. Mention --force-with-lease and how you would recover a botched rebase.
Own the policy question: which history shape the project wants, what that implies for contributor tooling and review, and the cost of enforcing linear history on outside contributors who rebase rarely.
## The situation You opened a change from a topic branch in your fork. Days pass, `upstream/main` moves, and your branch's merge base is now old. Before review — or before the maintainers can merge you — you want your branch to sit on current upstream code. Git offers two integrations, and they differ in exactly one respect: whether your commits keep their identity. ## Rebase ``` git fetch upstream git switch feature/parser git rebase upstream/main git push --force-with-lease origin feature/parser ``` Rebase takes the commits unique to your branch, replays them one at a time on top of `upstream/main`, and moves the branch pointer to the last replayed commit. Each replayed commit has a different parent and therefore a different SHA — they are new commits, not moved ones. What you get: - A branch whose merge base with `upstream/main` is upstream's current tip, so the branch's whole diff is exactly your change and nothing else. - Linear history: each of your commits can be read, tested, and reverted on top of today's code. - Conflicts resolved **per replayed commit**, which is precise but can mean resolving a related conflict several times across a long series. What it costs: the old commits are no longer on the branch, so the push to your fork is no longer a fast-forward and needs `--force-with-lease`. Anyone who fetched the old tip — a co-contributor, a colleague testing your branch — now holds commits that have vanished from the branch. ## Merge ``` git fetch upstream git switch feature/parser git merge upstream/main git push origin feature/parser ``` Merge creates one new commit with two parents: your previous tip and `upstream/main`. Your commits keep their SHAs, the push stays a fast-forward, and any conflict is resolved once, in one place. What it costs: your branch now contains upstream's commits as ancestors, so `git log` on the branch mixes their work with yours; each further sync adds another merge commit; and a reader has to mentally subtract upstream history to see what you actually changed. Comparing against the merge base still gives the right diff, but the commit series is no longer a clean story. ## The decision rule 1. **Is anyone else's work based on this branch?** If yes, merge. Rewriting a branch other people have built on forces every one of them to recover manually, and that risk beats any tidiness benefit. 2. **Is it only your branch in your own fork?** Rebase. This is the normal case: a fork topic branch has exactly one author with push rights, so rewriting is safe and the maintainers get a series that applies cleanly. 3. **Is the branch long-lived with repeated painful conflicts?** Reconsider. Repeated rebases mean re-resolving the same conflicts; `rerere.enabled` lets Git reuse recorded resolutions, and a single merge caps the cost at one resolution. 4. **Does the project state a preference?** Follow it. Many projects want a rebased, linear series; some accept merges. Their preference outranks yours. ## Do not confuse this with squashing Rebasing to a new base and collapsing your branch into one commit are separate decisions. `git rebase upstream/main` preserves your commit structure; flattening it is an interactive-rebase choice. Answer the base-refresh question first. ## Only rebase what you are prepared to republish Rebasing an already-pushed branch is fine precisely because a fork topic branch is yours. Two guardrails matter: use `--force-with-lease` rather than a bare force so the push is refused if the remote moved unexpectedly, and never apply this reasoning to a shared integration branch like `main`, where rewriting published history is a genuine incident. ## Recovering a botched rebase A rebase that goes wrong is recoverable: `git rebase --abort` mid-flight returns you to the starting point, and afterwards `ORIG_HEAD` still names the pre-rebase tip. Knowing that out loud is part of the confidence the question is testing. ## What interviewers are listening for Not a dogmatic "rebase is better". They want the tradeoff stated in terms of commit identity — rebase rewrites, merge does not — the consequence for publishing (force-push versus fast-forward), the consequence for readers, and a rule about shared branches. A candidate who says "rebase because it's cleaner" without mentioning that the branch's commits are replaced has not understood what the command does.
- Why does rebasing a fork topic branch require a force-push while merging does not?Rebase replays your commits onto a new base, so they get new SHAs and the branch tip is no longer a descendant of what your fork holds — the server rejects it as non-fast-forward. Merge only adds a commit on top of the existing tip, so it remains a fast-forward. Use `--force-with-lease` rather than a plain force for the rebase case.
- Your rebase hits the same conflict on three consecutive commits. What are your options?Rebase resolves per replayed commit, so a conflict touching all three recurs. You can enable `rerere.enabled` so Git replays your recorded resolutions automatically, restructure the series so the conflicting change lands once, or accept a single merge of `upstream/main` instead, which caps the resolution at one place.
- A rebase went badly and you already left the rebase. How do you get the old branch back?The pre-rebase tip is still recorded: `ORIG_HEAD` names it immediately after the rebase, and the branch's earlier positions remain in its reflog. Reset the branch to that commit to restore the original series. During the rebase itself, `git rebase --abort` returns you to the starting state directly.
saying these in an interview costs you the question
- Rebase is always better, with no mention of rewriting
- Rebasing a branch other contributors have built on
- Thinking rebase and squash are the same operation
- Using a bare force push after every rebase
- Believing merging upstream in changes the branch's final diff