# Cover lightweight tag creation in batched bootstrap

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

## Sessions

fbdb2b242248View transcript

### Changes

2

- docs
  - Mrewrite-issue-list.md+5/-1
- internal/syncer
  - Mintegration_test.go+43

### 1. Batched bootstrap can claim tag refs were pushed when no tag ref was created

Status: partial  
Status: done

Problem:  
- In the batched bootstrap tag phase, `FetchPack` returning `git.NoErrAlreadyUpToDate` can skip tag creation entirely even when the tag ref is absent and only the tag object is already reachable.

Comparison check:  
- A tag whose target object is already present on target must still be created during bootstrap.

Current rewrite note:  
- This is now covered directly for the lightweight-tag case where branch batches already made the target object reachable before tag creation.

### 2. Duplicate target mappings are silently accepted

Status: done

Current rewrite note:  
- Some of these are now covered, including empty source repo, tag force-retarget, duplicate/conflicting mappings, and tag creation when target objects already exist.
- Batched lightweight-tag creation without an extra pack is now covered directly.
- Basic context cancellation coverage now exists.
- Batched bootstrap resume mismatch and final-tip cutover paths now have direct integration coverage.
- Some harder batch-failure injection and partial cutover failure paths still remain.

```go
func TestBootstrap_IntegrationBatchedLightweightTagCreatesWithoutExtraPack(t *testing.T) {
    sourceRepo, sourceFS := newSourceRepo(t)
    makeLargeCommits(t, sourceRepo, sourceFS, 5, 200_000)
    sourceHead, err := sourceRepo.Reference(plumbing.NewBranchReferenceName(testBranch), true)
    if err != nil {
        t.Fatalf("resolve source head: %v", err)
    }
    if err := sourceRepo.Storer.SetReference(plumbing.NewHashReference(plumbing.NewTagReferenceName("v1"), sourceHead.Hash())); err != nil {
        t.Fatalf("set lightweight tag: %v", err)
    }

targetRepo, err := git.Init(memory.NewStorage(), nil)
    if err != nil {
        t.Fatalf("init target repo: %v", err)
    }

sourceServer := newSmartHTTPRepoServerV2(t, sourceRepo)
    targetServer := newSmartHTTPRepoServer(t, targetRepo)
    defer sourceServer.Close()
    defer targetServer.Close()

result, err := Bootstrap(context.Background(), Config{
        Source:            Endpoint{URL: sourceServer.RepoURL()},
        Target:            Endpoint{URL: targetServer.RepoURL()},
        ProtocolMode:      protocolModeAuto,
        IncludeTags:       true,
        BatchMaxPackBytes: 350_000,
    })
    if err != nil {
        t.Fatalf("batched bootstrap with lightweight tag failed: %v", err)
    }
    if result.Pushed != 2 || !result.Batching || result.RelayMode != "bootstrap-batch" {
        t.Fatalf("unexpected result: %+v", result)
    }
    tagRef, err := targetRepo.Reference(plumbing.NewTagReferenceName("v1"), true)
    if err != nil {
        t.Fatalf("resolve target tag: %v", err)
    }
    if tagRef.Hash() != sourceHead.Hash() {
        t.Fatalf("expected target tag %s, got %s", sourceHead.Hash(), tagRef.Hash())
    }
}

func TestBootstrap_IntegrationBranchMapping(t *testing.T) {
    sourceRepo, sourceFS := newSourceRepo(t)
    makeCommits(t, sourceRepo, sourceFS, 3)
}
```
