Expand incremental relay to tag creation · Entire

Expand incremental relay to tag creation

Sessions

90fce803a9eaView transcript

Changes

4

90 unmodified lines

91
92
93
94
94
95
96
97

90 unmodified lines

When `sync` sees that all managed target refs are absent and the run is compatible with bootstrap semantics, it automatically uses the bootstrap relay path instead of the normal decode-and-repack sync path.

`sync` also uses a narrow incremental relay path for fast-forward branch updates when all planned updates are branch-only, there are no tags, no prune/delete, no force, and the target does not advertise `no-thin`. This now includes multi-branch batches and branch-to-branch mappings. More complex updates still fall back to the normal local decode-and-repack path.
`sync` also uses a narrow incremental relay path for fast-forward branch updates and tag creation when there is no prune/delete, no force, and the target does not advertise `no-thin`. This now includes multi-branch batches, branch-to-branch mappings, and create-only tags. Tag retargeting and other more complex updates still fall back to the normal local decode-and-repack path.

Sync specific branches:

MREADME.md+1/-1

165 unmodified lines

166
167
168
169
169
170

165 unmodified lines

- there is now a narrow incremental relay path in `sync`
- it now covers multi-branch fast-forward branch-only updates
- it now also covers branch-to-branch mappings
- tags, deletes, force, and prune still use the normal path
- it now also covers create-only tags
- tag retargets, deletes, force, and prune still use the normal path

Mdocs/bootstrap.md+2/-1

290 unmodified lines

291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357

290 unmodified lines

assertGitRefEqual(t, sourceBare, targetBare, plumbing.NewBranchReferenceName(testBranch), plumbing.NewBranchReferenceName("stable"))

func TestRun_GitHTTPBackendSyncTagCreate(t *testing.T) {
    if os.Getenv(gitHTTPBackendEnv) == "" {
         t.Skip("set GITSYNC_E2E_GIT_HTTP_BACKEND=1 to run git-http-backend integration test")
    }

if _, err := exec.LookPath("git"); err != nil {
         t.Skipf("git not available: %v", err)
    }

root := t.TempDir()
    sourceBare := filepath.Join(root, "source.git")
    targetBare := filepath.Join(root, "target.git")
    worktree := filepath.Join(root, "work")

runGit(t, root, "init", "--bare", sourceBare)
    runGit(t, root, "init", "--bare", targetBare)
    runGit(t, targetBare, "config", "http.receivepack", "true")
    runGit(t, root, "init", "-b", testBranch, worktree)
    runGit(t, worktree, "config", "user.name", "git-sync test")
    runGit(t, worktree, "config", "user.email", "git-sync@example.com")

writeFile(t, filepath.Join(worktree, "README.md"), "tag\n")
    runGit(t, worktree, "add", "README.md")
    runGit(t, worktree, "commit", "-m", "initial")
    runGit(t, worktree, "remote", "add", "origin", sourceBare)
    runGit(t, worktree, "push", "origin", "HEAD:refs/heads/"+testBranch)

server := newGitHTTPBackendServer(t, root)
    defer server.Close()

sourceURL := server.RepoURL("source.git")
    targetURL := server.RepoURL("target.git")

if _, err := Run(context.Background(), Config{
        Source: Endpoint{URL: sourceURL},
        Target: Endpoint{URL: targetURL},
    }); err != nil {
        t.Fatalf("initial sync failed: %v", err)
    }

runGit(t, worktree, "tag", "v1")
    runGit(t, worktree, "push", "origin", "refs/tags/v1")

result, err := Run(context.Background(), Config{
        Source: Endpoint{URL: sourceURL},
        Target: Endpoint{URL: targetURL},
        IncludeTags: true,
    })
    if err != nil {
        t.Fatalf("tag-create sync failed: %v", err)
    }
    if result.Pushed != 1 || result.Blocked != 0 {
        t.Fatalf("unexpected tag-create result: %+v", result)
    }
    if !result.Relay || result.RelayMode != "incremental" {
        t.Fatalf("expected tag-create sync to use incremental relay, got %+v", result)
    }

assertGitRefEqual(t, sourceBare, targetBare, plumbing.NewTagReferenceName("v1"))
}

func TestBootstrap_GitHTTPBackendSync(t *testing.T) {
    if os.Getenv(gitHTTPBackendEnv) == "" {
         t.Skip("set GITSYNC_E2E_GIT_HTTP_BACKEND=1 to run git-http-backend integration test")
    }

Minternal/syncer/git_http_backend_test.go+61


758 unmodified lines

759
760
761
762
762
763
764
765
7 unmodified lines

773
774
775
776
777
778
779
780
781
782
783
784
785
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797

758 unmodified lines

}

func canIncrementalRelay(cfg Config, plans []BranchPlan, targetAdv *packp.AdvRefs) bool {
    if cfg.Force || cfg.Prune || cfg.DryRun || cfg.IncludeTags {
    if cfg.Force || cfg.Prune || cfg.DryRun {
        return false
    }
    if len(plans) == 0 {
    7 unmodified lines

}

for _, plan := range plans {
        if plan.Kind != RefKindBranch {
            return false
    }
        if !plan.SourceRef.IsBranch() || !plan.TargetRef.IsBranch() {
            return false
    }
        if plan.Action != ActionUpdate {
            return false
    }
        if plan.TargetHash.IsZero() {
        switch plan.Kind {
        case RefKindBranch:
            if !plan.SourceRef.IsBranch() || !plan.TargetRef.IsBranch() {
                return false
            }
            if plan.Action != ActionUpdate {
                return false
            }
            if plan.TargetHash.IsZero() {
                return false
            }
        case RefKindTag:
            if !plan.SourceRef.IsTag() || !plan.TargetRef.IsTag() {
                return false
            }
            if plan.Action != ActionCreate {
                return false
            }
        default:
            return false
        }
    }