This is an automated email from the ASF dual-hosted git repository.

klesh pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/devlake.git


The following commit(s) were added to refs/heads/main by this push:
     new 71dd14f75 fix(gitextractor): disable git auto gc/maintenance while 
cloning (#9218)
71dd14f75 is described below

commit 71dd14f75cd5e761a4d7a305a1d4ae7d7f137c00
Author: Dirk <[email protected]>
AuthorDate: Sun Oct 18 04:50:40 2026 +0200

    fix(gitextractor): disable git auto gc/maintenance while cloning (#9218)
    
    git fetch ends with `git maintenance run --auto` (older git: `git gc
    --auto`), which runs detached by default. During an incremental
    collection the last fetch can leave a background repack running while
    libgit2 already scans objects/pack/, so a temporary
    .tmp-<pid>-pack-*.idx disappears under it and Collect Commits fails
    intermittently with "could not find ... to open".
    
    Pass -c gc.auto=0 -c gc.autoDetach=false -c maintenance.auto=false to
    every git command run by GitcliCloner. The clone is a temporary
    directory, so automatic housekeeping has no benefit there; the
    explicit `git repack -d` in deepen() still runs synchronously.
    
    Add a regression test that traces an incremental clone with GIT_TRACE
    and asserts that git starts neither `maintenance run` nor `gc --auto`.
    
    Signed-off-by: DoDiODev <[email protected]>
---
 .../plugins/gitextractor/parser/clone_gitcli.go    |  8 ++++++
 .../gitextractor/parser/clone_gitcli_test.go       | 29 ++++++++++++++++++++++
 2 files changed, 37 insertions(+)

diff --git a/backend/plugins/gitextractor/parser/clone_gitcli.go 
b/backend/plugins/gitextractor/parser/clone_gitcli.go
index f61dbc10d..82fc9d57a 100644
--- a/backend/plugins/gitextractor/parser/clone_gitcli.go
+++ b/backend/plugins/gitextractor/parser/clone_gitcli.go
@@ -94,6 +94,14 @@ func NewGitcliCloner(ctx plugin.SubTaskContext, localDir 
string) (*GitcliCloner,
 
 func (g *GitcliCloner) prepareSync() errors.Error {
        taskData := g.taskData
+       // Disable automatic (detached) gc/maintenance after clone/fetch. 
Otherwise git may
+       // repack the repo in the background while libgit2 is already reading 
it, which
+       // makes temporary pack files (.tmp-<pid>-pack-*.idx) vanish and the 
collection fail.
+       g.globalConfigArgs = append(g.globalConfigArgs,
+               "-c", "gc.auto=0",
+               "-c", "gc.autoDetach=false",
+               "-c", "maintenance.auto=false",
+       )
        if *taskData.Options.SkipCommitStat {
                g.syncArgs = append(g.syncArgs, "--filter=blob:none")
        }
diff --git a/backend/plugins/gitextractor/parser/clone_gitcli_test.go 
b/backend/plugins/gitextractor/parser/clone_gitcli_test.go
index 49b6ea32d..790980f64 100644
--- a/backend/plugins/gitextractor/parser/clone_gitcli_test.go
+++ b/backend/plugins/gitextractor/parser/clone_gitcli_test.go
@@ -126,6 +126,35 @@ func TestIncrementalCloneKeepsCommitsBehindMergeBoundary(t 
*testing.T) {
        assert.True(t, newest.Before(*cloner.since), "shallow boundary %s 
should be older than since", newest)
 }
 
+// git fetch may start `git maintenance run --auto` / `git gc --auto` in the
+// background. That repacks the repo while libgit2 is already reading it, so
+// temporary pack files (.tmp-<pid>-pack-*.idx) vanish under its feet and the
+// collection fails with "could not find ... to open".
+func TestCloneDoesNotStartAutoMaintenance(t *testing.T) {
+       if _, err := exec.LookPath("git"); err != nil {
+               t.Skip("git is not installed")
+       }
+       origin, _ := buildMergeBoundaryRepo(t)
+       cloner := newTestCloner(t, origin, time.Date(2024, 1, 2, 12, 0, 0, 0, 
time.UTC))
+       skipCommitStat := false
+       cloner.taskData.Options.SkipCommitStat = &skipCommitStat
+       require.NoError(t, cloner.prepareSync())
+       traceFile := filepath.Join(t.TempDir(), "git-trace.log")
+       t.Setenv("GIT_TRACE", traceFile)
+
+       require.NoError(t, cloner.CloneRepo())
+
+       trace, e := os.ReadFile(traceFile)
+       require.NoError(t, e)
+       require.Contains(t, string(trace), "fetch", "the incremental clone 
should run git fetch")
+       for _, line := range strings.Split(string(trace), "\n") {
+               if strings.Contains(line, "run_command:") {
+                       assert.NotContains(t, line, "maintenance run", "git 
must not start automatic maintenance")
+                       assert.NotContains(t, line, "gc --auto", "git must not 
start automatic gc")
+               }
+       }
+}
+
 func TestNewestShallowCommitTimeIgnoresMissingCommits(t *testing.T) {
        if _, err := exec.LookPath("git"); err != nil {
                t.Skip("git is not installed")

Reply via email to