When to Use Force Push for Clean Git Branch Histories

Force-pushing is fine on personal branches and topic branches with no other contributors; it's a footgun anywhere else. The safer command is git push --force-with-lease (or --force-if-includes for the strictest variant) — these refuse the push if someone else moved the remote since your last fetch instead of overwriting blindly.

Prefer interactive rebase

For most "clean up the history before merging" cases, interactive rebase is the right tool — squash, fixup, reorder, drop, or reword commits in place:

1git rebase -i HEAD~5

You get an editor with each commit and a verb. Save and exit, resolve any conflicts (git rebase --continue / --abort), then push.

When rebase isn't enough: reset and cherry-pick

If you want to rebuild from a known-good commit and bring a small subset of later commits back, save your current state first (or trust reflog — see below):

1git branch backup 2git reset --hard <good-commit> 3git cherry-pick <commit-1> <commit-2>

git reset flags:

FlagHistoryIndexWorking tree
--softresetkeptkept
--mixed (default)resetresetkept
--hardresetresetdiscarded

--hard is destructive — anything not committed elsewhere is gone unless reflog still has it. Cherry-pick conflicts: resolve, git add, git cherry-pick --continue (or --abort).

Push safely

1git push --force-with-lease

--force-with-lease checks that the remote ref is at the position you last fetched. If someone else has pushed in between, it refuses — much better than --force, which silently overwrites their work. --force-if-includes (Git 2.30+, 2020) tightens this further by also requiring your local ref to be reachable from the remote ref.

Never force-push a shared branch (main, develop, anything with open PRs from other people).

If something goes wrong

Don't panic — git reflog keeps every prior HEAD position for ~90 days:

1git reflog 2git reset --hard HEAD@{3}

That's why a manual backup branch is usually overkill; reflog is the real safety net, and it's automatic.

When you're done and definitely happy with the new history, force-delete any manual backup branch you made:

1git branch -D backup

Plain -d will refuse: cherry-picked commits get new SHAs, so backup isn't an ancestor of HEAD.