Merge pull request #74 from entireio/fix/pack-less-ref-create-empty-pack · Entire
Merge pull request #74 from entireio/fix/pack-less-ref-create-empty-pack
2ace436→main·Soph·1mo ago·2 files·+144 added/-4 removed
Changes
internal/gitproto
Mpush.go+49/-4
- Mpush_test.go+95
import (
"bytes"
"context"
"crypto"
"errors"
"fmt"
"io"
"os"
"slices"
"strings"
"sync/atomic"
"time"
"github.com/go-git/go-git/v6/plumbing"
"github.com/go-git/go-git/v6/plumbing/format/packfile"
"github.com/go-git/go-git/v6/plumbing/hash"
"github.com/go-git/go-git/v6/plumbing/protocol/capability"
"github.com/go-git/go-git/v6/plumbing/protocol/packp"
"github.com/go-git/go-git/v6/plumbing/protocol/packp/sideband"
)
// PushCommands sends ref-only updates without a pack. // PushCommands sends ref-only updates. Creates/updates carry an empty pack; // delete-only pushes carry no pack. func (p *Pusher) PushCommands(ctx context.Context, commands []PushCommand) error { return PushCommands(ctx, p.Conn, p.Adv, commands, p.Verbose, p.OnRejection) }
// emptyPack returns a valid packfile containing zero objects whose trailing // checksum matches the target's advertised object format: SHA-256 repositories // get a 32-byte trailer; everything else uses the 20-byte SHA-1 trailer. func emptyPack(adv *packp.AdvRefs) []byte { if vals := adv.Capabilities.Get(capability.ObjectFormat); len(vals) > 0 && vals[0] == "sha256" { return emptyPackSHA256 } return emptyPackSHA1 }
func TestEmptyPackTrailerMatchesObjectFormat(t *testing.T) { t.Run("sha1 default", func(t *testing.T) { adv := &packp.AdvRefs{} pack := emptyPack(adv) require.Len(t, pack, 12+sha1.Size) require.Equal(t, emptyPackHeader, pack[:12]) sum := sha1.Sum(emptyPackHeader) require.Equal(t, sum[:], pack[12:])
// Golden: git's canonical empty-pack checksum. require.Equal(t, "029d08823bd8a8eab510ad6ac75c823cfd3ed31e", hex.EncodeToString(pack[12:])) }) }
// TestPushCommandsSendsEmptyPackForCreate guards the interop fix: a ref // create that moves no new objects must still carry a valid empty pack, so // receive-pack implementations that read a pack header for every non-delete // command don't see a truncated body. func TestPushCommandsSendsEmptyPackForCreate(t *testing.T) { // ... similar test logic follows }
// TestPushCommandsSendsNoPackForDeleteOnly checks that delete-only pushes // should not carry a pack. func TestPushCommandsSendsNoPackForDeleteOnly(t *testing.T) { // ... similar test logic follows }
func TestBuildUpdateRequest(t *testing.T) { adv := &packp.AdvRefs{} adv.Capabilities.Set(capability.ReportStatus) }`