Match hoist on SourceRef so --map remappings push the right target first · Entire
Match hoist on SourceRef so --map remappings push the right target first
833b123→main·
Soph·2mo ago·3 files·+91 added/-42 removed
Cursor caught a real bug: hoistSourceHeadCommand compared cmd.Name (which PlansToPushCommands sets from p.TargetRef) against sourceHEAD the source-side symref target). Under --map (e.g., master→stable), target ref name diverges from source — the match silently fails and the bootstrap pushes branches in alphabetical order, defeating the fix on the very setups that need it most (custom branch naming on mirror).
Rework to operate on plans instead of commands, matching SourceRef against sourceHEAD. The mapped TargetRef inherits its position in the plans slice, so PlansToPushCommands emits commands in the right order. Aligns with executeBatched's orderTrunkFirst which already keys on DesiredRef.SourceRef.
Regression test pins --map master:stable + a 1:1 alpha mapping: the target server's first command must be refs/heads/stable. Without the fix, the bootstrap pushes alpha first. Unit test gains a case asserting "matches on SourceRef, hoists mapped TargetRef".
Sessions
81dd3a769cb7View transcript
Changes
3
internal
strategy/bootstrap
- Mbootstrap.go+10/-9
Mbootstrap_test.go+34/-33
syncer
Mintegration_test.go+47
175 unmodified lines
176
177
178
179
180
179
180
181
182
13 unmodified lines
196
197
198
200
201
199
200
201
202
203
204
203
204
205
206
206
207
208
208
209
209
210
211
212
213
175 unmodified lines
if p.OnPhase != nil {
p.OnPhase("pushing pack")
}
cmds := convert.PlansToPushCommands(plans)
cmds = hoistSourceHeadCommand(cmds, p.SourceHeadTarget)
pushErr := p.TargetPusher.PushPack(ctx, cmds, packReader)
_ = packReader.Close()
if pushErr != nil {
13 unmodified lines
return result, nil
}
// hoistSourceHeadCommand moves the push command for the source's symref
// HEAD target to the front of cmds. Hosts that pick the default branch
// hoistSourceHeadPlan moves the plan whose source ref matches the
// source's symref HEAD target to the front, so the resulting push
// commands send that ref first. Hosts that pick the default branch
// from the first push on a fresh repo (GitHub, GitLab) end up with the
// right default.
func hoistSourceHeadCommand(cmds []gitproto.PushCommand, sourceHEAD plumbing.ReferenceName) []gitproto.PushCommand {
// right default. Matching is on SourceRef rather than TargetRef so
// --map remappings push the correct (mapped) target ref first.
func hoistSourceHeadPlan(plans []planner.BranchPlan, sourceHEAD plumbing.ReferenceName) []planner.BranchPlan {
if sourceHEAD == "" {
return cmds
}
return plans
}
Minternal/strategy/bootstrap/bootstrap.go+10/-9
21 unmodified lines
...
func TestHoistSourceHeadCommand(t *testing.T) {
func TestHoistSourceHeadPlan(t *testing.T) {
main := plumbing.NewBranchReferenceName("main")
master := plumbing.NewBranchReferenceName("master")
alpha := plumbing.NewBranchReferenceName("alpha")
stable := plumbing.NewBranchReferenceName("stable")
cmd := func(name plumbing.ReferenceName) gitproto.PushCommand {
return gitproto.PushCommand{Name: name}
}
plan := func(source, target plumbing.ReferenceName) planner.BranchPlan {
return planner.BranchPlan{SourceRef: source, TargetRef: target}
}
tests := []struct {
name string
cmds []gitproto.PushCommand
head plumbing.ReferenceName
wanted []plumbing.ReferenceName
name string
plans []planner.BranchPlan
head plumbing.ReferenceName
wantTargetRefs []plumbing.ReferenceName
}{
{
name: "hoists matching command to front",
cmds: []gitproto.PushCommand{cmd(alpha), cmd(main), cmd(master)},
head: main,
wanted: []plumbing.ReferenceName{main, alpha, master},
name: "hoists matching plan to front",
plans: []planner.BranchPlan{plan(alpha, alpha), plan(main, main), plan(master, master)},
head: main,
wantTargetRefs: []plumbing.ReferenceName{main, alpha, master},
},
...
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := hoistSourceHeadCommand(tt.cmds, tt.head)
... // remaining test code
}
}
Minternal/syncer/integration_test.go+47