muse push — have-negotiation ignores sibling refs on remote
Background
When pushing a branch to a remote, the push negotiation computes blobs_to_send
by comparing the local tip against the remote's tip for that specific branch only.
It does not account for objects already present on the remote via other refs.
Observed behaviour
After pushing dev to staging successfully (17 commits, 46 blobs), pushing main
to the same staging remote attempted to upload 1,375 commits and 379 MB of data —
failing with [Errno 32] Broken pipe.
Local main is staging/dev + one merge commit. The merge-base of local main and
local dev is exactly dev's tip (sha256:f9828e…). All objects are already present
on staging from the dev push. Only the merge commit itself needs to go over the wire.
Root cause
The "have" set used during push negotiation is scoped to the target branch's remote
tip. Objects reachable from other remote refs (e.g. staging/dev) are not included
in the have set, so the delta computation over-counts blobs_to_send by treating
already-uploaded objects as missing.
Expected behaviour
blobs_to_send should be computed against the union of all objects reachable from
all refs present on the remote — not just the branch being pushed. When main is a
direct descendant of dev and dev is already on the remote, the push for main
should send only the new commits and their net-new objects (in this case, one merge
commit and zero new blobs).
Impact
- Pushes to branches that lag behind a sibling ref on the same remote become disproportionately large.
- Large packs time out or hit broken-pipe errors even when no new data is needed.
- Workaround: push the most-advanced branch first (e.g.
dev), then accept thatmainmay still require a large redundant upload until this is fixed.