diff --git a/internal/gitclone/manager.go b/internal/gitclone/manager.go index 67e22c3..adbda38 100644 --- a/internal/gitclone/manager.go +++ b/internal/gitclone/manager.go @@ -352,6 +352,21 @@ func (r *Repository) executeClone(ctx context.Context) error { return errors.Wrapf(err, "configure fetch refspec: %s", string(output)) } + // Set git configs for optimal performance + configs := map[string]string{ + "pack.threads": "4", + "pack.windowMemory": "256m", + "repack.useDeltaBaseOffset": "true", + } + for key, value := range configs { + // #nosec G204 - r.path, key, and value are controlled by us + cmd = exec.CommandContext(ctx, "git", "-C", r.path, "config", key, value) + output, err = cmd.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "configure %s: %s", key, string(output)) + } + } + cmd, err = r.gitCommand(ctx, "-C", r.path, "-c", "http.postBuffer="+strconv.Itoa(config.PostBuffer), "-c", "http.lowSpeedLimit="+strconv.Itoa(config.LowSpeedLimit), @@ -365,6 +380,14 @@ func (r *Repository) executeClone(ctx context.Context) error { return errors.Wrapf(err, "fetch all branches: %s", string(output)) } + // Generate pack with bitmaps for fast object counting during clone operations + // #nosec G204 - r.path is controlled by us + cmd = exec.CommandContext(ctx, "git", "-C", r.path, "repack", "-adb") + output, err = cmd.CombinedOutput() + if err != nil { + return errors.Wrapf(err, "git repack with bitmaps: %s", string(output)) + } + return nil } diff --git a/internal/strategy/git/backend.go b/internal/strategy/git/backend.go index 9b0dd8d..c6a8083 100644 --- a/internal/strategy/git/backend.go +++ b/internal/strategy/git/backend.go @@ -68,6 +68,16 @@ func (s *Strategy) serveFromBackend(w http.ResponseWriter, r *http.Request, repo "GIT_PROJECT_ROOT=" + absRoot, "GIT_HTTP_EXPORT_ALL=1", "PATH=" + os.Getenv("PATH"), + // Optimize upload-pack performance + "GIT_CONFIG_COUNT=4", + "GIT_CONFIG_KEY_0=pack.threads", + "GIT_CONFIG_VALUE_0=4", + "GIT_CONFIG_KEY_1=pack.windowMemory", + "GIT_CONFIG_VALUE_1=256m", + "GIT_CONFIG_KEY_2=core.compression", + "GIT_CONFIG_VALUE_2=1", + "GIT_CONFIG_KEY_3=pack.compression", + "GIT_CONFIG_VALUE_3=1", }, } diff --git a/internal/strategy/git/bundle.go b/internal/strategy/git/bundle.go index 115609f..dc18163 100644 --- a/internal/strategy/git/bundle.go +++ b/internal/strategy/git/bundle.go @@ -21,6 +21,26 @@ func (s *Strategy) generateAndUploadBundle(ctx context.Context, repo *gitclone.R logger.InfoContext(ctx, "Bundle generation started", slog.String("upstream", upstream)) + // Run git maintenance to optimize repository before creating bundle + err := repo.WithReadLock(func() error { + // #nosec G204 - repo.Path() is controlled by us + cmd := exec.CommandContext(ctx, "git", "-C", repo.Path(), "repack", "-Adbl") + output, err := cmd.CombinedOutput() + if err != nil { + logger.WarnContext(ctx, "Git repack failed, continuing with bundle generation", + slog.String("upstream", upstream), + slog.String("error", err.Error()), + slog.String("output", string(output))) + } else { + logger.DebugContext(ctx, "Git repack completed", + slog.String("upstream", upstream)) + } + return nil + }) + if err != nil { + return errors.Wrap(err, "repack repository") + } + cacheKey := cache.NewKey(upstream + ".bundle") headers := http.Header{