ref: 43e244474fc5c77723f2d75382a1a730738dd364
parent: e0e56e63defc1cb9cc14081c62bb268de7e15dd7
author: Runxi Yu <me@runxiyu.org>
date: Fri Feb 20 07:41:23 EST 2026
Revert "packed, delta: Implement thin packs" This reverts commit 8e320c9ca634e6b2431f9442b7d5191864735ae4.
--- a/delta_write_select.go
+++ b/delta_write_select.go
@@ -8,7 +8,6 @@
body []byte
offset uint64
deltaDepth int
- inPack bool
}
type deltaContext struct {--- a/packed_write_pack.go
+++ b/packed_write_pack.go
@@ -283,40 +283,12 @@
// packWrite writes a pack stream for the provided object ids.
func (repo *Repository) packWrite(w io.Writer, objects []Hash, opts packWriteOptions) (Hash, error) {- if opts.EnableThinPack {- return Hash{}, errThinPackUnimplemented- }
- return repo.packWriteObjects(w, objects, opts, nil)
-}
-
-// packWriteReachable writes a pack stream for objects reachable from the
-// provided reachability query.
-func (repo *Repository) packWriteReachable(w io.Writer, query ReachabilityQuery, opts packWriteOptions) (Hash, error) { if repo == nil { return Hash{}, ErrInvalidObject}
- query.Mode = ReachabilityAllObjects
- walk, err := repo.ReachableObjects(query)
- if err != nil {- return Hash{}, err+ if opts.EnableThinPack {+ return Hash{}, errThinPackUnimplemented}
- var objects []Hash
- for obj := range walk.Seq() {- objects = append(objects, obj.ID)
- }
- if err := walk.Err(); err != nil {- return Hash{}, err- }
- return repo.packWriteObjects(w, objects, opts, walk)
-}
-
-func (repo *Repository) packWriteObjects(w io.Writer, objects []Hash, opts packWriteOptions, have *ReachabilityWalk) (Hash, error) {- if repo == nil {- return Hash{}, ErrInvalidObject- }
- if opts.EnableThinPack && have == nil {- return Hash{}, ErrInvalidObject- }
if len(objects) > int(^uint32(0)) { return Hash{}, ErrInvalidObject}
@@ -340,12 +312,6 @@
deltaSeed = binary.LittleEndian.Uint64(seedBytes[:])
}
- if opts.EnableDeltas && opts.EnableThinPack {- if err := repo.seedDeltaCandidatesFromHaves(&dctx, have.query.Haves); err != nil {- return Hash{}, err- }
- }
-
for _, id := range objects {ty, body, err := repo.ReadObjectTypeRaw(id)
if err != nil {@@ -352,10 +318,9 @@
return Hash{}, err}
obj := &objectToPack{- id: id,
- ty: ty,
- body: body,
- inPack: true,
+ id: id,
+ ty: ty,
+ body: body,
}
startOffset := pw.bytesWritten
wroteDelta := false
@@ -363,27 +328,11 @@
if opts.EnableDeltas && ty == ObjectTypeBlob {base, delta := pickDeltaBase(&dctx, obj, deltaSeed, opts.MinDeltaSavings, opts.MaxDeltaDepth)
if base != nil && delta != nil {- switch {- case base.inPack:
- if err := pw.WriteOfsDelta(base.offset, len(base.body), len(body), delta); err != nil {- return Hash{}, err- }
- wroteDelta = true
- obj.deltaDepth = base.deltaDepth + 1
- case opts.EnableThinPack:
- inHave, err := have.HaveContains(base.id)
- if err != nil {- return Hash{}, err- }
- if inHave {- if err := pw.WriteRefDelta(base.id, len(base.body), len(body), delta); err != nil {- return Hash{}, err- }
- wroteDelta = true
- obj.deltaDepth = base.deltaDepth + 1
- }
- default:
+ if err := pw.WriteOfsDelta(base.offset, len(base.body), len(body), delta); err != nil {+ return Hash{}, err}
+ wroteDelta = true
+ obj.deltaDepth = base.deltaDepth + 1
}
}
if !wroteDelta {@@ -400,39 +349,6 @@
}
return pw.Close()
-}
-
-func (repo *Repository) seedDeltaCandidatesFromHaves(ctx *deltaContext, haves []Hash) error {- if repo == nil {- return ErrInvalidObject
- }
- if ctx == nil || ctx.window <= 0 || len(haves) == 0 {- return nil
- }
- walk, err := repo.ReachableObjects(ReachabilityQuery{- Wants: haves,
- Mode: ReachabilityAllObjects,
- })
- if err != nil {- return err
- }
- for obj := range walk.Seq() {- if obj.Type != ObjectTypeBlob {- continue
- }
- ty, body, err := repo.ReadObjectTypeRaw(obj.ID)
- if err != nil {- return err
- }
- candidate := &objectToPack{- id: obj.ID,
- ty: ty,
- body: body,
- inPack: false,
- }
- ctx.addCandidate(candidate)
- }
- return walk.Err()
}
type packWriteOptions struct {--- a/packed_write_test.go
+++ b/packed_write_test.go
@@ -358,90 +358,6 @@
_ = gitCmd(t, repoPath, "fsck", "--full", "--strict")
}
-func TestPackWriteThinPackReachable(t *testing.T) {- repoPath, cleanup := setupTestRepo(t)
- defer cleanup()
-
- workDir, cleanupWork := setupWorkDir(t)
- defer cleanupWork()
-
- base := bytes.Repeat([]byte("A"), 16384)- if err := os.WriteFile(filepath.Join(workDir, "file.txt"), base, 0o644); err != nil {- t.Fatalf("write base file: %v", err)- }
- gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".")
- gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "base")
- haveHash := gitCmd(t, repoPath, "rev-parse", "HEAD")
-
- mod := append([]byte(nil), base...)
- mod[1024] = 'B'
- if err := os.WriteFile(filepath.Join(workDir, "file.txt"), mod, 0o644); err != nil {- t.Fatalf("write mod file: %v", err)- }
- gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".")
- gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "target")
- wantHash := gitCmd(t, repoPath, "rev-parse", "HEAD")
-
- repo, err := OpenRepository(repoPath)
- if err != nil {- t.Fatalf("OpenRepository failed: %v", err)- }
- defer func() { _ = repo.Close() }()-
- wantID, _ := repo.ParseHash(wantHash)
- haveID, _ := repo.ParseHash(haveHash)
-
- query := ReachabilityQuery{- Wants: []Hash{wantID},- Haves: []Hash{haveID},- Mode: ReachabilityAllObjects,
- StopAtHaves: true,
- }
- var buf bytes.Buffer
- if _, err := repo.packWriteReachable(&buf, query, packWriteOptions{- EnableDeltas: true,
- EnableThinPack: true,
- MinDeltaSavings: 1,
- }); err != nil {- t.Fatalf("packWriteReachable failed: %v", err)- }
-
- thinSeen, err := checkThinPackStream(buf.Bytes(), repo)
- if err != nil {- t.Fatalf("thin pack stream invalid: %v", err)- }
- if !thinSeen {- t.Fatalf("expected thin pack with ref-delta base outside pack")- }
-
- packDir := filepath.Join(repoPath, "objects", "pack")
- if err := os.MkdirAll(packDir, 0o755); err != nil {- t.Fatalf("failed to create pack dir: %v", err)- }
- packPath := filepath.Join(packDir, "furgit-thin-test.pack")
- idxPath := strings.TrimSuffix(packPath, ".pack") + ".idx"
- _ = os.Remove(packPath)
- _ = os.Remove(idxPath)
-
- cmd := exec.Command("git", "index-pack", "--stdin", "--fix-thin", "-o", idxPath, packPath)- cmd.Dir = repoPath
- cmd.Env = append(os.Environ(),
- "GIT_CONFIG_GLOBAL=/dev/null",
- "GIT_CONFIG_SYSTEM=/dev/null",
- )
- cmd.Stdin = bytes.NewReader(buf.Bytes())
- output, err := cmd.CombinedOutput()
- if err != nil {- t.Fatalf("git index-pack --fix-thin failed: %v\n%s", err, output)- }
-
- _ = gitCmd(t, repoPath, "cat-file", "-p", wantHash)
- _ = gitCmd(t, repoPath, "fsck", "--full", "--strict")
-
- _ = os.Remove(packPath)
- _ = os.Remove(idxPath)
-}
-
func checkPackStream(path string, algo hashAlgorithm, objectCount int) error {data, err := os.ReadFile(path)
if err != nil {@@ -586,134 +502,6 @@
}
}
return nil
-}
-
-func checkThinPackStream(data []byte, repo *Repository) (bool, error) {- if repo == nil {- return false, ErrInvalidObject
- }
- if len(data) < 12 {- return false, ErrInvalidObject
- }
- if binary.BigEndian.Uint32(data[0:4]) != packMagic || binary.BigEndian.Uint32(data[4:8]) != packVersion2 {- return false, ErrInvalidObject
- }
- count := int(binary.BigEndian.Uint32(data[8:12]))
- pos := 12
- hashSize := repo.hashAlgo.Size()
- type objEntry struct {- offset uint64
- ty ObjectType
- body []byte
- }
- byOffset := make(map[uint64]objEntry, count)
- byHash := make(map[string]objEntry, count)
- thinSeen := false
-
- for i := 0; i < count; i++ {- objOffset := uint64(pos)
- ty, size, consumed, err := packHeaderParse(data[pos:])
- if err != nil {- return thinSeen, fmt.Errorf("obj %d header at %d: %v", i, pos, err)- }
- pos += consumed
- baseTy := ObjectTypeInvalid
- var baseBody []byte
- switch ty {- case ObjectTypeOfsDelta:
- dist, distConsumed, err := packDeltaReadOfsDistance(data[pos:])
- if err != nil {- return thinSeen, fmt.Errorf("obj %d ofs at %d: %v", i, pos, err)- }
- pos += distConsumed
- if dist == 0 || dist > objOffset {- return thinSeen, fmt.Errorf("obj %d ofs at %d: invalid dist", i, pos)- }
- baseOffset := objOffset - dist
- base, ok := byOffset[baseOffset]
- if !ok {- return thinSeen, fmt.Errorf("obj %d ofs at %d: missing base", i, pos)- }
- baseTy = base.ty
- baseBody = base.body
- case ObjectTypeRefDelta:
- if pos+hashSize > len(data) {- return thinSeen, ErrInvalidObject
- }
- var baseHash Hash
- copy(baseHash.data[:], data[pos:pos+hashSize])
- baseHash.algo = repo.hashAlgo
- baseEntry, ok := byHash[baseHash.String()]
- if ok {- baseTy = baseEntry.ty
- baseBody = baseEntry.body
- } else {- thinSeen = true
- ty, body, err := repo.ReadObjectTypeRaw(baseHash)
- if err != nil {- return thinSeen, err
- }
- baseTy = ty
- baseBody = body
- }
- pos += hashSize
- default:
- }
-
- payloadBuf, zconsumed, err := zlibx.DecompressSized(data[pos:], size)
- if err != nil {- return thinSeen, fmt.Errorf("obj %d zlib at %d: %v", i, pos, err)- }
- payload := append([]byte(nil), payloadBuf.Bytes()...)
- payloadBuf.Release()
- pos += zconsumed
- switch ty {- case ObjectTypeOfsDelta, ObjectTypeRefDelta:
- if baseBody == nil {- return thinSeen, fmt.Errorf("obj %d missing base body", i)- }
- pos := 0
- baseSize, err := packVarintRead(payload, &pos)
- if err != nil {- return thinSeen, fmt.Errorf("obj %d delta base size: %v", i, err)- }
- resultSize, err := packVarintRead(payload, &pos)
- if err != nil {- return thinSeen, fmt.Errorf("obj %d delta result size: %v", i, err)- }
- if baseSize != len(baseBody) {- return thinSeen, fmt.Errorf("obj %d delta base size mismatch: got %d want %d", i, baseSize, len(baseBody))- }
- out, err := packDeltaApply(bufpool.FromOwned(baseBody), bufpool.FromOwned(payload))
- if err != nil {- return thinSeen, fmt.Errorf("obj %d delta apply: %v", i, err)- }
- body := append([]byte(nil), out.Bytes()...)
- out.Release()
- if resultSize != len(body) {- return thinSeen, fmt.Errorf("obj %d delta result size mismatch: got %d want %d", i, len(body), resultSize)- }
- byOffset[objOffset] = objEntry{offset: objOffset, ty: baseTy, body: body}- default:
- if size >= 0 && len(payload) != size {- return thinSeen, fmt.Errorf("obj %d size mismatch: got %d want %d", i, len(payload), size)- }
- body := append([]byte(nil), payload...)
- byOffset[objOffset] = objEntry{offset: objOffset, ty: ty, body: body}- }
-
- entry := byOffset[objOffset]
- if entry.body != nil && entry.ty != ObjectTypeInvalid {- hdr, err := headerForType(entry.ty, entry.body)
- if err != nil {- return thinSeen, err
- }
- raw := append(hdr, entry.body...)
- hash := repo.hashAlgo.Sum(raw)
- byHash[hash.String()] = entry
- }
- }
- return thinSeen, nil
}
func removeLooseObject(repoPath, oid string) error {--
⑨