Wire --all-refs into the CLI surface · Entire
Wire --all-refs into the CLI surface
07d05d5→main·Soph·2mo ago·7 files·+48 added/-1 removed
Adds --all-refs to sync, plan, replicate, bootstrap, fetch, and probe. For sync/plan/replicate/bootstrap the flag bundles AllRefs scope with BestEffort policy: the broader ref discovery only earns its keep when hidden-ref refusals downgrade to warnings instead of tanking the run. Probe and fetch get AllRefs as scope-only (neither pushes), with a tailored flag description so the help text doesn't lie about "warnings".
The unstable BootstrapRequest grows a BestEffort field so the CLI's RunE can mirror the sync-side coupling. Library callers keep the two halves decoupled via RefScope.AllRefs and SyncPolicy.BestEffort.
docs/usage.md documents the --all-refs example, the strict/best-effort split, and adds "warned" to the JSON output keys list.
Sessions
011ba13b7e3d View transcript
[?
do we have integration tests? Claude Code·Opus 4.7·1 step](/content/gh/entireio/git-sync/session/d0406407-d612-489d-b375-1372d062af82#timeline-011ba13b7e3d/index.html)
Changes
7
cmd/git-sync
Mbootstrap.go+4
Mfetch.go+1
Mflags.go+10
Mprobe.go+1
Msyncplan.go+4
docs
Musage.md+23/-1
unstable
Mclient.go+5
28 unmodified lines
SilenceUsage: true, RunE: func(cmd *cobra.Command, args []string) error { req.Protocol = gitsync.ProtocolMode(protocolVal) if req.Scope.AllRefs { req.BestEffort = true }
if req.Source.URL == "" && len(args) > 0 { req.Source.URL = args[0] } }
cmd.Flags().StringVar(&branches, "branch", "", "comma-separated branch list; default is all source branches") cmd.Flags().StringArrayVar(&mappings, "map", nil, "ref mapping in src:dst form; short names map branches, full refs map exact refs") cmd.Flags().BoolVar(&req.IncludeTags, "tags", false, "mirror tags") allRefsFlag(cmd, &req.Scope.AllRefs) cmd.Flags().BoolVar(&req.Options.CollectStats, "stats", false, "print transfer statistics") cmd.Flags().BoolVar(&req.Options.MeasureMemory, "measure-memory", false, "sample elapsed time and Go heap usage") cmd.Flags().BoolVar(&req.Options.Progress, "progress", false, "show live per-side throughput on stderr (TTY only)")
Mcmd/git-sync/bootstrap.go+4
68 unmodified lines
cmd.Flags().StringVar(&branches, "branch", "", "comma-separated branch list; default is all source branches") cmd.Flags().BoolVar(&req.IncludeTags, "tags", false, "include tags in the fetch request") cmd.Flags().BoolVar(&req.Scope.AllRefs, "all-refs", false, "include every refs/* on the source (notes, pulls, custom namespaces) in the fetch request") addProtocolFlag(cmd, &protocolVal) cmd.Flags().BoolVar(&req.Options.CollectStats, "stats", false, "print transfer statistics") cmd.Flags().BoolVar(&req.Options.MeasureMemory, "measure-memory", false, "sample elapsed time and Go heap usage")
Mcmd/git-sync/fetch.go+1
45 unmodified lines
cmd.Flags().Var(mode, "protocol", "protocol mode: auto, v1, or v2")
// allRefsFlag registers --all-refs. The CLI semantic is "mirror everything // from source on a best-effort basis" — callers must propagate AllRefs to // BestEffort inside RunE after flag parsing (cobra has no on-set hook), so // per-ref rejections become warnings on top of the broader scope. func allRefsFlag(cmd *cobra.Command, allRefs bool) { cmd.Flags().BoolVar(allRefs, "all-refs", false, "mirror every refs/ on the source (notes, pulls, custom namespaces) on a best-effort basis; "+ "per-ref server rejections become warnings rather than failing the sync") }
func newProtocolFlag() protocolModeFlag { return protocolModeFlag(protocolMode(envOr("GITSYNC_PROTOCOL", validation.ProtocolAuto))) }
Mcmd/git-sync/flags.go+10
64 unmodified lines
addTargetAuth(cmd, &targetAuth)
cmd.Flags().BoolVar(&req.IncludeTags, "tags", false, "include tag ref prefixes in probe") cmd.Flags().BoolVar(&req.AllRefs, "all-refs", false, "advertise all refs/* prefixes (notes, pulls, custom namespaces) in the probe") addProtocolFlag(cmd, &protocolVal) cmd.Flags().BoolVar(&req.Options.CollectStats, "stats", false, "print transfer statistics") cmd.Flags().BoolVar(&req.Options.MeasureMemory, "measure-memory", false, "sample elapsed time and Go heap usage")
Mcmd/git-sync/probe.go+1
42 unmodified lines
RunE: func(cmd *cobra.Command, args []string) error { req.Policy.Mode = gitsync.OperationMode(modeValue) req.Policy.Protocol = gitsync.ProtocolMode(protocolVal) if req.Scope.AllRefs { req.Policy.BestEffort = true }
if req.Source.URL == "" && len(args) > 0 { req.Source.URL = args[0] } }
cmd.Flags().BoolVar(&req.Policy.IncludeTags, "tags", false, "mirror tags") cmd.Flags().BoolVar(&req.Policy.Force, "force", false, "allow non-fast-forward branch updates and retarget tags") cmd.Flags().BoolVar(&req.Policy.Prune, "prune", false, "delete managed target refs that no longer exist on source") allRefsFlag(cmd, &req.Scope.AllRefs) cmd.Flags().BoolVar(&req.Options.CollectStats, "stats", false, "print transfer statistics") cmd.Flags().BoolVar(&req.Options.MeasureMemory, "measure-memory", false, "sample elapsed time and Go heap usage") cmd.Flags().BoolVar(&req.Options.Progress, "progress", false, "show live per-side throughput on stderr (TTY only)")
Mcmd/git-sync/syncplan.go+4
154 unmodified lines
Mirror every ref namespace (notes, pulls, custom) on a best-effort basis:
git-sync sync \
--all-refs \
<source-url> \
<target-url>
--all-refs broadens the source ref discovery from refs/heads/+refs/tags/
to every refs/* namespace and lets ref mappings target arbitrary
namespaces (refs/notes/*, refs/pull/*, custom refs). It also turns on
best-effort failure handling: when the target's receive-pack rejects an
individual ref (e.g. GitHub refusing writes to refs/pull/* hidden refs),
the rejected ref appears in the result with action=warn and the server's
reason instead of failing the whole sync. Pack-level transport or unpack
failures remain fatal.
Library callers can decouple the two halves: RefScope.AllRefs controls
scope alone, and SyncPolicy.BestEffort controls failure handling. The
CLI bundles them under --all-refs for convenience.
Force source-side protocol v2:
11 unmodified lines
- keys use `camelCase`
- refs and hashes are serialized as strings, not raw byte arrays
- top-level keys include `plans`, `pushed`, `skipped`, `blocked`, `deleted`, `dryRun`, `protocol`, and `stats`, plus `relay`, `relayMode`, `relayReason`, `batching`, `batchCount`, `plannedBatchCount`, and `tempRefs`
- each item in `plans` includes stable string fields such as `branch`, `sourceRef`, `targetRef`, `sourceHash`, `targetHash`, `kind`, `action`, and `reason`
## Auth