Simplify after review · Entire

Simplify after review

1ce7b69→main·

Soph·2mo ago·4 files·+23 added/-24 removed

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

Sessions

604f682ccdc6View transcript

Changes

4

594 unmodified lines

if err == nil {

t.Fatal("expected --force-with-lease and --force-blind together to be rejected")
}
if !strings.Contains(err.Error(), "mutually exclusive") {
if !strings.Contains(err.Error(), "force-with-lease") || !strings.Contains(err.Error(), "force-blind") {

t.Fatalf("unexpected error: %v", err)
}
}

Mcmd/git-sync/main_test.go+1/-1

42 unmodified lines

SilenceUsage:  true,
RunE: func(cmd *cobra.Command, args []string) error {
if legacyForce {
return errors.New("--force has been removed; use --force-with-lease (previous --force semantics: receive-pack rejects updates where the target moved during the run) or --force-blind (true overwrite, matches `git push --force`)")
}
if req.Policy.ForceWithLease && req.Policy.ForceBlind {
return errors.New("--force-with-lease and --force-blind are mutually exclusive")
}
req.Policy.Mode = gitsync.OperationMode(modeValue)
req.Policy.Protocol = gitsync.ProtocolMode(protocolVal)
}

if err := cmd.Flags().MarkHidden("force"); err != nil {
panic(err)
}
cmd.MarkFlagsMutuallyExclusive("force-with-lease", "force-blind")
cmd.Flags().BoolVar(&req.Policy.Prune, "prune", false, "delete managed target refs that no longer exist on source")

Mcmd/git-sync/syncplan.go+2/-4

59 unmodified lines

// PlansToPushCommands converts planner BranchPlans directly to gitproto PushCommands.
//
// When forceBlind is true, the expected-old hash is zeroed for non-delete
// commands. This tells receive-pack to overwrite regardless of the current
// target tip — matching `git push --force` semantics. Delete commands always
// carry the captured target hash so the server can confirm what it is removing.
//
// When forceBlind is false (the default), commands carry the target hash
// captured at session start; receive-pack rejects updates where the target
// moved during the run, providing per-run `--force-with-lease` protection.
// When forceBlind is true, non-delete commands send a zero expected-old so
// receive-pack overwrites regardless of current target value; see SyncPolicy.
func PlansToPushCommands(plans []planner.BranchPlan, forceBlind bool) []gitproto.PushCommand {
out := make([]gitproto.PushCommand, len(plans))
for i, p := range plans {

Minternal/convert/convert.go+2/-9

104 unmodified lines

return req, hasDelete, hasUpdates, nil
// annotateLeaseFailure wraps a CommandStatusErr whose status looks like a
// lease failure (target ref moved during the sync, or the captured expected-old
// no longer matches) with a hint pointing users at the retry/override path.
// Other receive-pack errors pass through unchanged.
// leaseFailureMarkers are receive-pack ng reason substrings that indicate the
// captured target tip didn't match what was on the server at push time. Match
// is case-insensitive. CommandStatusErr.Status is a free-form string in go-git,
// so substring matching is the only option absent upstream sentinels.
var leaseFailureMarkers = []string{
"stale info",
"fetch first",
"non-fast-forward",
"does not match",
}

// annotateLeaseFailure wraps a lease-failure CommandStatusErr with a retry/
// override hint. Other receive-pack errors pass through unchanged.
func annotateLeaseFailure(err error) error {
var cs *packp.CommandStatusErr
if !errors.As(err, &cs) {
return err
}
status := strings.ToLower(cs.Status)
if !strings.Contains(status, "stale info") &&
!strings.Contains(status, "fetch first") &&
!strings.Contains(status, "non-fast-forward") &&
!strings.Contains(status, "does not match") {
return err
for _, marker := range leaseFailureMarkers {
if strings.Contains(status, marker) {
return fmt.Errorf("%w (target ref %s moved or differs from session start; rerun, or use --force-blind to overwrite)", err, cs.ReferenceName)
}
}
return fmt.Errorf("%w (target ref %s moved or differs from session start; rerun, or use --force-blind to overwrite)", err, cs.ReferenceName)
}
return err
}

// sendReceivePack encodes and POSTs a receive-pack request, then decodes the report.

Minternal/gitproto/push.go+18/-10