diff --git a/modules/git/archive.go b/modules/git/archive.go index 159db42011..4259b8db1f 100644 --- a/modules/git/archive.go +++ b/modules/git/archive.go @@ -39,10 +39,11 @@ func CreateArchive(ctx context.Context, repo RepositoryFacade, repoName, format // CreateBundle create bundle content to the target path func CreateBundle(ctx context.Context, repo RepositoryFacade, commit string, out io.Writer) error { - // TODO: use the following steps instead of creating a temp file, also need to iterate and clean up outdated refs - // git update-ref refs/bundle/temp-{timestamp} {commit} - // git bundle create - refs/bundle/temp-{timestamp} - // git update-ref -d refs/bundle/temp-{timestamp} + // TODO: use the following steps instead of creating a temp repo, also need to iterate and clean up outdated refs + // the temp ref has to be under refs/heads/*, and a clone only checks out with a HEAD, which needs the temp repo + // git update-ref refs/heads/bundle-temp-{timestamp} {commit} + // git bundle create - refs/heads/bundle-temp-{timestamp} + // git update-ref -d refs/heads/bundle-temp-{timestamp} tmpDir, cleanup, err := setting.AppDataTempDir("git-repo-content").MkdirTempRandom("gitea-bundle") if err != nil { return err @@ -69,18 +70,5 @@ func CreateBundle(ctx context.Context, repo RepositoryFacade, commit string, out return err } - tmpFile := filepath.Join(tmpDir, "bundle") - _, _, err = gitTmpCmd().AddArguments("bundle", "create").AddDynamicArguments(tmpFile, "bundle", "HEAD").RunStdString(ctx) - if err != nil { - return err - } - - fi, err := os.Open(tmpFile) - if err != nil { - return err - } - defer fi.Close() - - _, err = io.Copy(out, fi) - return err + return gitTmpCmd().AddArguments("bundle", "create", "-", "bundle", "HEAD").WithStdoutCopy(out).RunWithStderr(ctx) } diff --git a/modules/git/archive_test.go b/modules/git/archive_test.go new file mode 100644 index 0000000000..18a05dc48d --- /dev/null +++ b/modules/git/archive_test.go @@ -0,0 +1,29 @@ +// Copyright 2026 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package git + +import ( + "bytes" + "strings" + "testing" + + "gitea.dev/modules/setting" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestCreateBundle(t *testing.T) { + setting.AppDataPath = t.TempDir() + + buf := &bytes.Buffer{} + require.NoError(t, CreateBundle(t.Context(), mockRepository("repo1_bare"), "ce064814f4a0d337b333e646ece456cd39fab612", buf)) + + header, _, ok := strings.Cut(buf.String(), "\n\n") + require.True(t, ok) + assert.Equal(t, "# v2 git bundle", strings.Split(header, "\n")[0]) + // without a refs/heads/* ref and a HEAD, a clone of the bundle has no branch and no checkout + assert.Contains(t, header, "ce064814f4a0d337b333e646ece456cd39fab612 refs/heads/bundle") + assert.Contains(t, header, "ce064814f4a0d337b333e646ece456cd39fab612 HEAD") +}