Split --force into --force-with-lease and --force-blind

main

Commit

Soph4mo ago

The previous --force was always lease-protected: PlansToPushCommands sent the captured session-start target hash as the push command's expected-old, and receive-pack rejected updates where the target had moved during the run. The name oversold the danger — it never matched git push --force's raw clobber semantics.

Replace with two explicit flags matching git push's surface:

  • --force-with-lease — previous behavior (allow non-FF, send captured target tip as expected-old; server rejects on lease miss).
  • --force-blind — new path; zero the expected-old for non-delete commands so receive-pack overwrites regardless of current target value. Matches git push --force.

The two are mutually exclusive. Legacy --force errors out with a migration hint pointing at both replacements (pre-0.5, no installed script base to preserve). bootstrap and replicate continue to reject force flags entirely.

SyncPolicy.Force splits into ForceWithLease + ForceBlind on the public API; syncer.Config grows a ForceAny() helper for the internal "allow non-FF" sense (planner permissiveness). convert.PlansToPushCommands takes a forceBlind bool; incremental/materialized strategies plumb it from cfg, others pass false since bootstrap/replicate reject force.

Closes the rename portion of #47.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com Entire-Checkpoint: a733497c4d7f

Checkpoints

can you rebase soph/progress-indicators onto soph/smart-subdivision

Claude Code
View session
Checkpoint 1

can you look at https://github.com/entireio/git-sync/issues/46 and then chat

Claude CodeOpus 4.7[1m]
View session
Checkpoint 1