History Is Messy, So Force-Push a Clean main?
Scenario
The main branch has picked up some clutter: a few merge commits, plus a change that was reverted and then un-reverted, leaving a noisy trail. Four people actively work in this repository, each with a local clone, and several feature branches are in flight — all based on main as it exists today. A teammate has already prepared a rebased, linear version of main locally that reads beautifully.
The Quick Fix on the Table
Push the polished history over the shared branch with git push --force. The argument: it is a quick, low-risk cleanup — the code at the tip is identical, only the history changes, and the log becomes pleasant to read.
The quick fix is on the table and the room is waiting for your call. Would you sign off on it? Take a position and justify it — out loud or on paper — before revealing the analysis.
Why the Quick Fix Fails
- Every clone and branch is now based on ghosts. Rebasing rewrites commit IDs. All four contributors' local main branches — and every feature branch built on them — point at commits that no longer exist upstream. The "cleanup" is instantly everyone's problem.
- The blast radius is invisible until people pull. Colleagues hit diverged-branch errors at random times over the following days, and the untrained reflex response —
git pullcreating a merge of old and new history — quietly reintroduces the exact mess the rewrite was meant to remove. - Someone will lose work. Under pressure to resolve the divergence, a hard reset in the wrong direction or a bad conflict resolution discards commits. Recovering them from reflogs costs far more time than the messy log ever did.
- Everything that references history breaks. CI runs, deploy records, review links and issue references are pinned to commit hashes that just vanished. Traceability — the actual point of history — is what gets destroyed by "cleaning" it.
- The benefit is cosmetic. Merge commits and a revert/un-revert pair are accurate records of what happened. A pretty log is nice; it is not worth a multi-day, four-person disruption.
The interviewer nods: “Fine, the quick fix is off the table. So what exactly would you do — step by step?” Sketch your plan before revealing the approach.
The Right Approach
- Leave published history alone. Adopt the rule that shared branches are append-only: mistakes on main are corrected by new commits —
git revert— never by rewriting what others have already pulled. - Protect main so this can't happen by accident. Enable branch protection on the hosting platform to block force-pushes and deletions on main, and require pull requests for changes.
- Get clean history the safe way: at merge time. Adopt squash merges (or rebase-and-merge) as the PR policy — each feature lands as one tidy commit, and the linear log everyone wants emerges naturally from now on.
- Let authors polish before publishing. Rebasing and squashing your own unpushed work —
git rebase -ion a private feature branch — is where interactive rebase belongs; the boundary is whether anyone else has built on the commits. - If a rewrite is ever truly unavoidable (for example a leaked secret), treat it as a coordinated operation: announce a freeze, have everyone push their work, rewrite once, then have every contributor re-clone or hard-reset with explicit instructions — and rotate the secret anyway, since history lives in every clone.
- Redirect the energy into readable commits going forward. Meaningful commit messages and small PRs improve the log's usefulness far more than retroactive surgery does.
Final pushback: “Your plan costs more time and money than the quick fix. Convince me.” How do you defend your position under pressure?
How to Defend It
- "The rewrite isn't low-risk — it invalidates every clone and every feature branch in the team the moment it lands. Four people pay for one person's tidy log."
- "Messy history is a cosmetic issue; rewritten shared history is an operational one. Only one of those pages anyone at 9am on Monday."
- "We can have the clean history we want from today onward with squash merges — same aesthetic result, zero disruption, no one re-cloning anything."
- "Those merge commits and the revert pair are the true story of the branch. History is a record, not a marketing document."
- "Let's turn this into policy instead of a one-off: branch protection blocking force-pushes, squash merges on PRs. Then this debate never comes back."