feat(client): sync --force to escape the locally-modified skip

Managed items with local modifications were kept (skip + warn) with no
escape hatch other than deleting the deployed file by hand — after an
upstream change the deployed content silently stayed old, which reads
exactly like a stale cache.

--force turns the two skip cases into update (repository version wins)
and remove (upstream deleted + modified). Unmanaged items and never-
managed path occupancies stay untouched even with --force; the default
behavior is unchanged.
This commit is contained in:
m3ta-chiron committed 2026-10-02 12:34:57 +02:00
1 parent 2017329015
commit 1ab97bff43
6 files changed
+164 -14

No files matched your search

+4 -2
View File
@@ -12,11 +12,13 @@ import (
// SyncOptions parameterize a client sync run. RepoURL (with optional Ref)
// is the inline --repo override: it works without any config file and beats
// a repo_url discovered in the config chain.
// a repo_url discovered in the config chain. Force switches the planner
// from skip+warn to overwrite for locally modified managed items.
type SyncOptions struct {
ConfigPath string
RepoURL string
Ref string
Force bool
}
// prepared is everything sync and status share: the pulled repository, the
@@ -80,7 +82,7 @@ func prepare(opts SyncOptions) (*prepared, error) {
path, _ := oc.DeployPath(typ, name)
return path
}
plan := Plan(items, manifest, diskFacts(oc, manifest, items), pathFor)
plan := Plan(items, manifest, diskFacts(oc, manifest, items), pathFor, opts.Force)
for _, e := range plan {
if !safePath(e.DstPath) {
return nil, fmt.Errorf("refusing unsafe deploy path %q", e.DstPath)