fix(git): silence getWorktrees warning when directory is not a repo

`getWorktrees` logs a warn-level line every time the managed OpenCode
process or any other caller passes a directory that is not inside a
git repository. The OpenChamber desktop main.log fills with hundreds
of these "Failed to list worktrees, returning empty list: fatal: not
a git repository ..." entries over a normal session.

The empty-list fallback is already correct (worktrees are an optional
feature), but the warning is noise that hides real git failures. Use
the existing `isNotGitRepositoryError` helper to suppress the warn
specifically for the "not a git repository" case and keep the
warning for genuine failures (lock contention, permission errors,
corrupt repos, etc.).
This commit is contained in:
herjarsa
2026-08-10 00:20:12 +02:00
parent 4e7eb81036
commit 629bf40d83
2 changed files with 52 additions and 2 deletions
+9 -1
View File
@@ -3738,7 +3738,15 @@ export async function getWorktrees(directory) {
path: entry.worktree,
}));
} catch (error) {
console.warn('Failed to list worktrees, returning empty list:', error?.message || error);
// Worktrees are an optional feature. When the caller passes a directory
// that is not inside any git repository (for example, the managed
// OpenCode's working directory or an unconfigured project path), git
// exits with "fatal: not a git repository ...". Treat that as an
// authoritative empty result so the route handler can still respond
// 200 [] and the desktop main.log stays free of noise.
if (!isNotGitRepositoryError(error)) {
console.warn('Failed to list worktrees, returning empty list:', error?.message || error);
}
return [];
}
}
+43 -1
View File
@@ -2,7 +2,7 @@ import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';
import { afterEach, describe, expect, it } from 'vitest';
import { afterEach, describe, expect, it, vi } from 'vitest';
import simpleGit from 'simple-git';
import {
@@ -13,6 +13,7 @@ import {
getBranches,
getRangeDiff,
getStatus,
getWorktrees,
isGitRepository,
populateWorktreeWithLockRecovery,
removeWorktree,
@@ -460,6 +461,47 @@ describe('worktree root resolution', () => {
});
});
// ---------------------------------------------------------------------------
// getWorktrees
// ---------------------------------------------------------------------------
describe('getWorktrees', () => {
if (!canRunGit()) {
it.skip('git binary not available', () => {});
return;
}
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
afterEach(() => {
warnSpy.mockClear();
});
it('returns an empty list for a non-git directory without warning', async () => {
const nonGit = createTempDir();
const result = await getWorktrees(nonGit);
expect(result).toEqual([]);
expect(warnSpy).not.toHaveBeenCalled();
});
it('returns the worktrees for a real git repository', async () => {
const repo = createTempDir();
runGit(repo, ['init', '-b', 'main']);
runGit(repo, ['config', 'user.email', 'test@example.com']);
runGit(repo, ['config', 'user.name', 'Test User']);
fs.writeFileSync(path.join(repo, 'README.md'), '# Test\n');
runGit(repo, ['add', 'README.md']);
runGit(repo, ['commit', '-m', 'init']);
const result = await getWorktrees(repo);
expect(Array.isArray(result)).toBe(true);
expect(warnSpy).not.toHaveBeenCalled();
});
});
// ---------------------------------------------------------------------------
// createWorktree
// ---------------------------------------------------------------------------