# Merge pull request #74 from entireio/fix/pack-less-ref-create-empty-pack

`2ace436`→[main](/content/gh/entireio/git-sync/commits/main/index.html)·Soph·1mo ago·2 files·+144 added/-4 removed

## Changes

- internal/gitproto

- Mpush.go+49/-4
  - Mpush_test.go+95

```go
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)
}`
