Plumb TargetHEAD through Result/ProbeResult/bridge · Entire
Plumb TargetHEAD through Result/ProbeResult/bridge
e470b83·
Soph·2mo ago·2 files·+24 added/-9 removed
syncer.Result and syncer.ProbeResult re-gain the TargetHEAD field. internalbridge.ProbeResult.TargetHEAD and ExecutionSummary.TargetHEAD expose it to library callers / JSON output. Human Lines() emit a "target-head: " line when populated.
All Result construction sites (sync, replicate, bootstrap wrapper) pick up s.target.headTarget. ProbeResult does the same in the s.target != nil branch.
Together with the previous commit's upload-pack discovery, callers can now see both sides of the HEAD picture and decide what to do — git-sync still doesn't actively propagate HEAD over the wire (no go-git symref-update support yet), but the field-equality check is enough for a CLI script or downstream tool to detect a default-branch mismatch.
Refs #45.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com
Sessions
0b4edbe8a55fView transcript
[?
do we have integration tests?Claude Code·Opus 4.7[1m]·1 step](/content/gh/entireio/git-sync/session/d0406407-d612-489d-b375-1372d062af82#timeline-0b4edbe8a55f/index.html)
Changes
2
internal/syncer
Msyncer.go+20/-9
internalbridge
Mmodel.go+4
130 unmodified lines
131
132
133
134
135
136
137
138
139
134
135
136
137
138
139
140
141
142
12 unmodified lines
155
156
157
158
159
160
161
23 unmodified lines
185
186
187
188
189
190
191
192
193
8 unmodified lines
202
203
204
205
206
207
208
10 unmodified lines
219
220
221
222
223
224
225
226
227
503 unmodified lines
731
732
733
726
734
735
736
737
37 unmodified lines
775
776
777
770
778
779
780
781
80 unmodified lines
862
863
864
865
866
867
868
12 unmodified lines
881
882
883
884
885
886
887
190 unmodified lines
1078
1079
1080
1071
1081
1082
1083
1084
100 unmodified lines
1185
1186
1187
1188
1189
1190
1191
130 unmodified lines
// Result holds the outcome of a sync or bootstrap operation.
//
// SourceHEAD carries the source's symref HEAD target as read from the
// upload-pack advertisement. It lets callers compare against the target's
// intended default branch without scraping the notice stream. Target HEAD
// is not exposed here because the receive-pack advertisement we already
// perform doesn't include HEAD; surfacing target HEAD would need a
// separate upload-pack round-trip and is tracked as a follow-up.
// SourceHEAD and TargetHEAD carry each side's symref HEAD target. Source
// is parsed from the upload-pack advertisement we already make. Target
// requires an additional upload-pack info-refs round-trip (the
// receive-pack advertisement omits HEAD by protocol design); when that
// fails — push-only auth, empty target where HEAD's underlying ref
// doesn't exist — TargetHEAD is empty.
type Result struct {
Plans []BranchPlan `json:"plans"`
Pushed int `json:"pushed"`
12 unmodified lines
TempRefs []string `json:"tempRefs"`
BootstrapSuggested bool `json:"bootstrapSuggested"`
SourceHEAD plumbing.ReferenceName `json:"sourceHead,omitempty"`
TargetHEAD plumbing.ReferenceName `json:"targetHead,omitempty"`
Stats Stats `json:"stats"`
Measurement Measurement `json:"measurement"`
Protocol string `json:"protocol"`
23 unmodified lines
if r.SourceHEAD != "" {
lines = append(lines, "source-head: "+r.SourceHEAD.String())
}
if r.TargetHEAD != "" {
lines = append(lines, "target-head: "+r.TargetHEAD.String())
}
return lines
}
8 unmodified lines
TargetCaps []string `json:"targetCapabilities,omitempty"`
Refs []RefInfo `json:"refs"`
SourceHEAD plumbing.ReferenceName `json:"sourceHead,omitempty"`
TargetHEAD plumbing.ReferenceName `json:"targetHead,omitempty"`
Stats Stats `json:"stats"`
Measurement Measurement `json:"measurement"`
}
10 unmodified lines
if r.SourceHEAD != "" {
lines = append(lines, "source-head: "+r.SourceHEAD.String())
}
if r.TargetHEAD != "" {
lines = append(lines, "target-head: "+r.TargetHEAD.String())
}
if len(r.Capabilities) > 0 {
lines = append(lines, "source-capabilities: "+strings.Join(r.Capabilities, ", "))
}
503 unmodified lines
Plans: plans, DryRun: true, RelayReason: reason,
OperationMode: modeSync, BootstrapSuggested: true, Stats: stats.snapshot(),
Measurement: measurementDone(), Protocol: sourceService.Protocol,
SourceHEAD: sourceService.HeadTarget,
SourceHEAD: sourceService.HeadTarget, TargetHEAD: s.target.headTarget,
}, nil
}
return bootstrapWithInputs(ctx, s, desiredRefs, targetRefMap, reason)
37 unmodified lines
result := Result{
Plans: plans, DryRun: s.cfg.DryRun, OperationMode: modeSync, Protocol: sourceService.Protocol,
Stats: stats.snapshot(), Measurement: measurementDone(),
SourceHEAD: sourceService.HeadTarget,
SourceHEAD: sourceService.HeadTarget, TargetHEAD: s.target.headTarget,
}
pushPlans := make([]BranchPlan, 0, len(plans))
80 unmodified lines
Measurement: s.measurementDone(),
Protocol: s.sourceService.Protocol,
SourceHEAD: s.sourceService.HeadTarget,
TargetHEAD: s.target.headTarget,
}, nil
}
return bootstrapWithInputs(ctx, s, desiredRefs, s.target.refMap, "empty-target-managed-refs")
12 unmodified lines
Stats: s.stats.snapshot(),
Measurement: s.measurementDone(),
SourceHEAD: s.sourceService.HeadTarget,
TargetHEAD: s.target.headTarget,
}
pushPlans := make([]BranchPlan, 0, len(plans))
190 unmodified lines
Batching: bResult.Batching, BatchCount: bResult.BatchCount,
PlannedBatchCount: bResult.PlannedBatchCount, TempRefs: bResult.TempRefs,
Stats: s.stats.snapshot(), Measurement: s.measurementDone(), Protocol: s.sourceService.Protocol,
SourceHEAD: s.sourceService.HeadTarget,
SourceHEAD: s.sourceService.HeadTarget, TargetHEAD: s.target.headTarget,
}, nil
}
}
100 unmodified lines
if s.target != nil {
result.TargetURL = s.cfg.Target.URL
result.TargetCaps = gitproto.AdvRefsCaps(s.target.adv)
result.TargetHEAD = s.target.headTarget
result.Stats = s.stats.snapshot()
result.Measurement = s.measurementDone()
}
``
Minternal/syncer/syncer.go+20/-9
``
87 unmodified lines
88
89
90
91
92
93
94
21 unmodified lines
116
117
118
119
120
121
122
18 unmodified lines
141
142
143
144
145
146
147
22 unmodified lines
170
171
172
173
174
175
176
87 unmodified lines
TargetCaps []string `json:"targetCapabilities,omitempty"`
Refs []RefInfo `json:"refs"`
SourceHEAD string `json:"sourceHead,omitempty"`
TargetHEAD string `json:"targetHead,omitempty"`
Stats Stats `json:"stats"`
Measurement Measurement `json:"measurement"`
}
21 unmodified lines
Reason string `json:"reason"`
BootstrapSuggested bool `json:"bootstrapSuggested"`
SourceHEAD string `json:"sourceHead,omitempty"`
TargetHEAD string `json:"targetHead,omitempty"`
Batch BatchSummary `json:"batch"`
}
18 unmodified lines
TargetCaps: append([]string(nil), result.TargetCaps...),
Refs: make([]RefInfo, 0, len(result.Refs)),
SourceHEAD: result.SourceHEAD.String(),
TargetHEAD: result.TargetHEAD.String(),
Stats: FromStats(result.Stats),
Measurement: FromMeasurement(result.Measurement),
}
22 unmodified lines
Reason: result.RelayReason,
BootstrapSuggested: result.BootstrapSuggested,
SourceHEAD: result.SourceHEAD.String(),
TargetHEAD: result.TargetHEAD.String(),
Batch: BatchSummary{
Enabled: result.Batching,
Planned: result.PlannedBatchCount,