From 83f5355ea13fbb2a2db18e3f9f7577a829a2740a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Flor=C3=AAncio?= Date: Sun, 5 Apr 2026 21:32:47 +0100 Subject: [PATCH] fix: skip git polling when workspace has no valid git repository (#541) --- .../server/process/workspace_git_poll.go | 8 ++++ .../server/process/workspace_monitor.go | 9 +++++ .../server/process/workspace_monitor_test.go | 39 +++++++++++++++++++ 3 files changed, 56 insertions(+) diff --git a/apps/backend/internal/agentctl/server/process/workspace_git_poll.go b/apps/backend/internal/agentctl/server/process/workspace_git_poll.go index 56c27f84e9..d8d2e3f119 100644 --- a/apps/backend/internal/agentctl/server/process/workspace_git_poll.go +++ b/apps/backend/internal/agentctl/server/process/workspace_git_poll.go @@ -17,6 +17,14 @@ import ( func (wt *WorkspaceTracker) pollGitChanges(ctx context.Context) { defer wt.wg.Done() + // If no valid git index was found at startup, git commands will fail. + // Exit immediately to avoid repeated rev-parse probes on a non-repo directory. + if wt.gitIndexPath == "" { + wt.logger.Warn("no valid git repository found, git polling not started", + zap.String("workDir", wt.workDir)) + return + } + ticker := time.NewTicker(wt.gitPollInterval) defer ticker.Stop() diff --git a/apps/backend/internal/agentctl/server/process/workspace_monitor.go b/apps/backend/internal/agentctl/server/process/workspace_monitor.go index 0e0d2ccf29..feec019ab3 100644 --- a/apps/backend/internal/agentctl/server/process/workspace_monitor.go +++ b/apps/backend/internal/agentctl/server/process/workspace_monitor.go @@ -35,6 +35,15 @@ const maxConsecutiveGitFailures = 5 func (wt *WorkspaceTracker) monitorLoop(ctx context.Context) { defer wt.wg.Done() + // If no valid git index was found at startup, there's nothing to poll. + // Exit immediately to avoid spamming "git diff-files: exit status 128" warnings + // every poll cycle until the consecutive failure threshold is reached. + if wt.gitIndexPath == "" { + wt.logger.Warn("no valid git repository found, file monitor not polling", + zap.String("workDir", wt.workDir)) + return + } + ticker := time.NewTicker(wt.filePollInterval) defer ticker.Stop() diff --git a/apps/backend/internal/agentctl/server/process/workspace_monitor_test.go b/apps/backend/internal/agentctl/server/process/workspace_monitor_test.go index c53ce6d429..fc338c2454 100644 --- a/apps/backend/internal/agentctl/server/process/workspace_monitor_test.go +++ b/apps/backend/internal/agentctl/server/process/workspace_monitor_test.go @@ -43,6 +43,45 @@ func TestWorkspaceTracker_StopsWhenWorkDirDeleted(t *testing.T) { } } +func TestWorkspaceTracker_MonitorExitsWhenNoGitRepo(t *testing.T) { + isolateTestGitEnv(t) + + // Create a plain directory with no git repo — resolveGitIndexPath returns "" + plainDir, err := os.MkdirTemp("", "test-no-git-*") + if err != nil { + t.Fatalf("failed to create temp dir: %v", err) + } + t.Cleanup(func() { _ = os.RemoveAll(plainDir) }) + + log := newTestLogger(t) + wt := NewWorkspaceTracker(plainDir, log) + // Use 500ms intervals so the 5-failure threshold takes ~2.5s. + // The fix should make monitorLoop exit immediately (well under 500ms). + wt.filePollInterval = 500 * time.Millisecond + wt.gitPollInterval = 500 * time.Millisecond + + if wt.gitIndexPath != "" { + t.Fatalf("expected empty gitIndexPath for non-git directory, got %q", wt.gitIndexPath) + } + + wt.Start(context.Background()) + + // monitorLoop should exit immediately without attempting git commands. + // Without the fix, it takes ~2.5s (5 failures × 500ms poll interval). + done := make(chan struct{}) + go func() { + wt.wg.Wait() + close(done) + }() + + select { + case <-done: + // Both goroutines exited quickly — success + case <-time.After(1 * time.Second): + t.Fatal("workspace tracker did not stop promptly when started without a valid git repo") + } +} + func TestWorkspaceTracker_StopsWhenGitBroken(t *testing.T) { isolateTestGitEnv(t)