pub fn emit_pack<'p>(
entries: &'p [EmitEntry],
hash: GitHashKind,
out: &mut dyn Write,
stored_of: &dyn Fn(usize) -> Result<&'p [u8]>,
) -> Result<EmitReport>Expand description
Assemble ordered entries into a packfile.
§What this does and does not do
It copies. Every entry’s compressed payload goes out byte for byte as
payload_of hands it over; nothing here inflates, deflates or computes a
delta. The only thing rewritten is the entry header, and only because
OFS_DELTA carries a distance that is relative to a position in the input
pack. An entry whose payload the caller rebuilt says so in
EmitEntry::recompressed and is counted apart, so the receipt names which
of the two happened rather than assuming.
entries must already be in topological_order and must be closed —
every OFS_DELTA base present. A base that is absent is an error here
rather than a silently dropped back-reference, because the alternative is a
pack whose closure does not hold and a client that discovers it.
The caller supplies stored_of, which borrows entry i’s whole stored
bytes — header included. Splitting it that way keeps this function free of
any opinion about where bytes live: they may be a slice of a mapping of the
archive, a slice of an owned buffer the caller rebuilt, or anything else that
outlives the call.
§Why the WHOLE entry and not the payload
It used to be payload_of, handing over stored[header_len..], and the
header the caller had just stripped was then re-parsed here anyway — for
the stated size, and for a REF_DELTA’s base oid. Three readings of one
varint across two files, and the caller’s header_len had to agree with this
function’s type_and_size or a ref-delta went out with its base named twice
(which it once did: git index-pack --strict answered inflate returned 1).
One reading, in one place, is LAW 5’s fix by construction.
§It streams, and it borrows — P-018 and P-025
Two properties, both deliberate, both previously absent:
stored_ofreturns&[u8], notVec<u8>. It used to return an owned buffer, which isP-025in its exact form:data.to_owned(), one heap allocation per object served, on a path whose entire claim is that it copies stored bytes without touching them. It is indexed by entry rather than handed an&EmitEntryso that the bytes may live outside the entry — which since 2026-08-14 they do: anEntryBytes::Extentis an address, and the bytes it names are a slice of the mapped archive.- The pack goes to
outas it is built, and the trailer is hashed incrementally. It used to accumulate the whole pack in aVec<u8>and hash it at the end, so serving a 2 GiB clone meant holding 2 GiB. The one fact the old shape got for free — the output offset anOFS_DELTAdistance is measured against — is counted here instead, which is cheaper than the buffer that was carrying it.
What is emphatically not here is gix’s pack pipeline: no counting pass
with a serial reduce, no sort_by over counts, no BTreeMap reorder, no
hashing of every byte on a consuming thread. Those are P-018’s serial tail,
and this function is the reason none of it is needed — the bytes are already
deflated and already delta-encoded, so emitting is a copy and an addition.