how/collaboration
Why --force-with-lease exists, exactly how it protects you from overwriting someone else's commits, and why a background fetch can fool it. Three zones, five scenarios.
git push --force is one of those tools you should not
use until you understand what it does. It overwrites the remote
history with yours silently, even if someone pushed there after
you. One bad push and other people's commits disappear from the
shared remote.
git push --force-with-lease is the safe counterpart. It checks
that the remote branch is the same one you last saw through
git fetch. If it is not, it refuses.
For this to work, Git has three zones, not two:
fetch. This is not
the remote, it is your idea of the remote.Press ▶ and watch how these three references diverge and why one of them can betray you.
The baseline. You just made a commit on feat, you did not rebase, and nobody else pushed to feat.
local feat = X
origin/feat (tracking) = X
remote feat = X
git push goes as a normal fast-forward: your local moved one
commit ahead, the remote is the ancestor. No force is needed here, and no
traps.
This is where all three zones start: local, origin/feat, remote.
Next we will watch how they diverge.
recap
What to remember:
--force overwrites the remote silently. If, between your last fetch
and your push, someone committed to the same branch, their commit
disappears with no warning.--force-with-lease takes the SHA from your
refs/remotes/origin/feat (what you last saw) and
compares it to the real SHA on the remote. If they differ, it refuses
with "stale info" and the other person's commit is saved.refs/remotes/origin/feat
silently updated to someone else's fresh SHA. The lease matches the remote,
the force goes through, and the other person's commit is overwritten.git push --force-with-lease=feat:<sha>, where <sha> is the one
you actually saw and deliberately decided to overwrite. The comparison
is against that SHA, not against the remote-tracking ref.main/master, force-push must be blocked by branch
protection. That is a safety net at the bottom so nobody's stray fingers
can reach it.A rule for your fingers: never --force, always
--force-with-lease. It helps to set up an alias:
git config --global alias.pushf 'push --force-with-lease'