- Add v1.1.0 and v1.2.0 changelog entries - Add exclude field to config reference and example config - Add ADRs documenting all major design decisions - Fix step numbering in reverse_sync() - Fix action.yml to copy VERSION file - Add dist/ and .env to .gitignore - Use refs/tags/ format for Nix flake tag refs Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1.6 KiB
1.6 KiB
ADR-003: Force-with-Lease for Forward Sync
Status: Accepted Date: 2026-01
Context
Forward sync pushes monorepo changes to the subrepo. If someone pushes directly to the subrepo between when josh-sync reads its HEAD and when josh-sync pushes, a naive git push would overwrite their work. A git push --force would be worse — it would silently destroy concurrent changes.
Decision
Use git push --force-with-lease=refs/heads/<branch>:<expected-sha> for all forward sync pushes. The expected SHA is recorded at the start of the sync operation (the "lease").
How it works
- Record subrepo HEAD SHA before any operations:
subrepo_sha=$(subrepo_ls_remote "$branch") - Perform merge of monorepo changes onto subrepo state
- Push with explicit lease:
--force-with-lease=refs/heads/main:<subrepo_sha> - If the subrepo HEAD changed since step 1, git rejects the push
- Josh-sync reports
lease-rejectedand retries on the next run
Consequences
Positive:
- Never overwrites concurrent changes — git atomically checks the expected SHA
- Explicit SHA lease (not just "current tracking ref") prevents stale-ref bugs
- Failed leases are retried on the next sync run — no data loss, just delay
- Works correctly with josh-proxy's SHA mapping
Negative:
- Lease-rejected means the sync run did work that gets discarded (clone, merge, etc.)
- Persistent lease failures indicate a concurrent push pattern that needs investigation
- Requires the
--force-with-leaseflag with explicit SHA — the shorthand form (--force-with-leasewithout=) is unsafe because it uses the local tracking ref, which may be stale