plumbing: packp, refactor AdvRefs and capability packages#1984
Closed
aymanbagabas wants to merge 13 commits into
Closed
plumbing: packp, refactor AdvRefs and capability packages#1984aymanbagabas wants to merge 13 commits into
aymanbagabas wants to merge 13 commits into
Conversation
Add internal init() method that creates the map on first write. NewList()
is deprecated; its body now returns &List{}.
…dation type Capability = string eliminates conversion friction for protocol v2. Remove known/requiresArgument/multipleArgument maps and error types. Add/Set no longer return errors; update all call sites.
…String Remove method List.Decode, add package-level DecodeList for v0/v1 space-separated wire format. Keep List.String for encoding. Wire format decoding now lives in the capability package as a free function rather than a method, making List a pure container.
Move plumbing/protocol/packp/capability to plumbing/protocol/capability to match git protocol structure and prepare for v2.
Remove deprecated NewList() in favor of the zero value. Fix capability ordering to ensure deterministic encoding.
Replace AdvRefs.References (map[string]Hash) and Peeled (map[string]Hash) with a single References []*plumbing.Reference slice. Remove NewAdvRefs(), AddReference(), IsEmpty(), and MakeReferenceSlice(). Change Capabilities from *capability.List to capability.List. This makes AdvRefs zero-value safe: slices are appendable from nil, and Capabilities is a value type. Add IsPeeled(), RefsToMap(), PeeledToMap() helpers to plumbing/reference.go. DecodeList and IsEmpty get nil-receiver guards.
Remove NewUploadRequest, NewUpdateRequests, and NewReportStatus. Their types are now zero-value safe: slices are appendable from nil, and Capabilities is a value type. The encoder guards against nil Depth. Set Depth to DepthCommits(0) in the decoder so decoded requests always have a non-nil Depth.
Replace the Depth sum-type interface (DepthCommits, DepthSince, DepthReference) with a single DepthRequest struct containing Commits, Since, and NotRefs fields. This matches git upload_pack_data struct, supports the full protocol (deepen-since + deepen-not combination, multiple deepen-not refs), and makes the zero value safe. Update encoder, decoder, and all consumers.
…plumbing Remove exported IsPeeled, RefsToMap, and PeeledToMap from plumbing/reference.go. Move isPeeled and peeledToMap as internal functions in the packp package. Update tests to iterate References directly instead of using helper functions.
Move the peeled check from internal packp function to ReferenceName.IsPeeled(), consistent with other reference name predicates like IsTag() and IsBranch(). Remove the internal isPeeled function and update all call sites to use ref.Name().IsPeeled() instead.
Remove state machine pattern from AdvRefs encoder and decoder. The original implementation had complex state functions (encodeFirstLine, encodeRefs, encodeShallow, encodeFlush for encoder; decodeFirstHash, decodeFirstRef, decodeCaps, decodeOtherRefs, decodeShallow for decoder). New encoder: single Encode method with sequential steps. New decoder: single Decode method with sequential loop. Add ReferenceName.IsPeeled helper and use it throughout. Move isPeeled and peeledToMap as internal functions in packp package. Remove exported IsPeeled, RefsToMap, PeeledToMap from plumbing.
c2b1c7e to
b1c082d
Compare
b1c082d to
1b9ba5f
Compare
Prevent combining deepen <n> with deepen-since or deepen-not, following canonical git's validation in upload-pack.c: `deepen and deepen-since (or deepen-not) cannot be used together` Add validation to both encoder and decoder, with tests for all invalid combinations.
1b9ba5f to
cad62f8
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR refactors the
plumbing/protocol/packppackage to simplify the AdvRefs encoder/decoder, clean up the capability package, and remove unnecessary constructors.Motivation
AdvRefs loses information
The old
AdvRefsstored references in two maps (ReferencesandPeeled) that lost wire-order information. Most consumers calledMakeReferenceSlice()immediately—the maps were an intermediate representation nobody wanted. The git pack protocol defines advertised-refs as an ordered sequence where peeled refs follow their base ref. The current representation didn't preserve this.Capability type forces conversions
Capabilitywas a defined type requiring conversions likecapability.Capability("custom-cap"). Protocol v2's arbitrary command capabilities multiply this friction. A type alias eliminates conversions while keeping the named constants.capability.List validation is counterproductive
List.Add()andSet()returned errors that callers universally discarded. Every call site discards the error. The validation maps enforce rules that callers already know. Worse, theknownmap becomes a liability for v2: unknown capabilities bypass validation silently.Constructors exist only to initialize maps
Every packp constructor (
NewAdvRefs,NewUploadRequest, etc.) existed primarily to callcapability.NewList(), which existed tomake(map[...]). IfListis zero-value safe, all constructors become unnecessary.Changes
capability.List zero-value safety
List.Add(),Set(), and other methodsListzero-value safe—first write creates the internal mapNewList()—use&List{}or zero valueCapability type alias
type Capability stringtotype Capability = stringAdd/Setinfallible (no error return)Wire format moved out of List
List.Decodewith package-levelDecodeListListprotocol-agnostic: it's now a pure container typeAdvRefs slice migration
References map[string]HashandPeeled map[string]Hashwith singleReferences []*ReferencesliceReferenceName.IsPeeled()helper (consistent withIsTag(),IsBranch())NewAdvRefs(),AddReference(),MakeReferenceSlice(),IsEmpty()AdvRefs encoder/decoder simplification
Encode()method)Decode()method with loop)Constructor removal and zero-value safety
NewUploadRequest,NewUpdateRequests,NewReportStatusappend,Capabilitiesis value typeDepthRequest struct replaces Depth interface
The old
Depthinterface used a sum-type pattern (DepthCommits,DepthSince,DepthReference) that couldn't represent the full git protocol. Specifically:deepen-sincewithdeepen-not(git allows this)deepen-notrefs (git uses an oidset)The new
DepthRequeststruct matches how canonical git C handles it:This matches git's
upload_pack_datastruct which stores depth as separate fields, not a sum type. The zero value (all fields empty/zero) means "no depth constraint" which is the correct default for infinite depth.Added validation: Following canonical git, the encoder and decoder now reject invalid combinations:
deepen <n>cannot be combined withdeepen-sinceordeepen-not"deepen and deepen-since (or deepen-not) cannot be used together"Benchmarks
Before (transport-migrate/base: 3 runs):
After (packp-refactoring: 3 runs):
Improvement:
Migration Guide
packp.NewAdvRefs()&packp.AdvRefs{}ar.References["name"] = hashar.References = append(ar.References, plumbing.NewHashReference("name", hash))capability.NewList()&capability.List{}caps.Decode(data)capability.DecodeList(data, &caps)depth := DepthCommits(3)depth := DepthRequest{Commits: 3}Testing
All existing tests pass:
go test ./plumbing/protocol/packp/...go test ./plumbing/protocol/capability/...make validatepasses (0 lint issues)