fix: git errors on startup / check
This commit is contained in:
@@ -392,6 +392,11 @@ export class GitEngine {
|
||||
return normalized.includes('no upstream branch') || normalized.includes('has no upstream branch');
|
||||
}
|
||||
|
||||
private isSpawnBadFileDescriptorError(message: string): boolean {
|
||||
const normalized = message.toLowerCase();
|
||||
return normalized.includes('spawn ebadf');
|
||||
}
|
||||
|
||||
private async getCurrentBranchName(git: ReturnType<typeof simpleGit>): Promise<string | null> {
|
||||
try {
|
||||
const status = await git.status();
|
||||
@@ -717,24 +722,36 @@ export class GitEngine {
|
||||
}
|
||||
|
||||
async getHistory(projectPath: string, limit = 20): Promise<GitHistoryEntry[]> {
|
||||
const git = simpleGit(projectPath);
|
||||
const git = this.createNonInteractiveGit(projectPath);
|
||||
const status = await git.status();
|
||||
const localHistory = await git.log({ maxCount: limit });
|
||||
|
||||
const mapLocalHistory = (): GitHistoryEntry[] => localHistory.all.map((entry) => ({
|
||||
hash: entry.hash,
|
||||
shortHash: entry.hash.slice(0, 7),
|
||||
date: entry.date,
|
||||
subject: entry.message,
|
||||
author: entry.author_name,
|
||||
syncStatus: 'local-only',
|
||||
}));
|
||||
|
||||
if (!status.tracking) {
|
||||
return localHistory.all.map((entry) => ({
|
||||
hash: entry.hash,
|
||||
shortHash: entry.hash.slice(0, 7),
|
||||
date: entry.date,
|
||||
subject: entry.message,
|
||||
author: entry.author_name,
|
||||
syncStatus: 'local-only',
|
||||
}));
|
||||
return mapLocalHistory();
|
||||
}
|
||||
|
||||
const behindCount = typeof status.behind === 'number' ? status.behind : Number(status.behind ?? 0);
|
||||
const remoteHistoryLimit = Math.max(limit, limit + Math.max(behindCount, 0));
|
||||
const remoteHistory = await git.log([status.tracking, '--max-count', String(remoteHistoryLimit)]);
|
||||
let remoteHistory;
|
||||
|
||||
try {
|
||||
remoteHistory = await git.log([status.tracking, '--max-count', String(remoteHistoryLimit)]);
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error ?? '');
|
||||
if (this.isSpawnBadFileDescriptorError(message)) {
|
||||
return mapLocalHistory();
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
type CommitLike = {
|
||||
hash: string;
|
||||
|
||||
@@ -434,6 +434,37 @@ describe('GitEngine', () => {
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should fall back to local history when remote history lookup fails with spawn EBADF', async () => {
|
||||
mockStatus.mockResolvedValue({ current: 'main', tracking: 'origin/main' });
|
||||
mockLog
|
||||
.mockResolvedValueOnce({
|
||||
all: [
|
||||
{
|
||||
hash: 'abc123def456',
|
||||
date: '2026-02-16T10:00:00.000Z',
|
||||
message: 'feat: local commit',
|
||||
author_name: 'Local Dev',
|
||||
},
|
||||
],
|
||||
})
|
||||
.mockRejectedValueOnce(new Error('Error: spawn EBADF'));
|
||||
|
||||
const result = await gitEngine.getHistory('/tmp/project', 20);
|
||||
|
||||
expect(mockLog).toHaveBeenNthCalledWith(1, { maxCount: 20 });
|
||||
expect(mockLog).toHaveBeenNthCalledWith(2, ['origin/main', '--max-count', '20']);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
hash: 'abc123def456',
|
||||
shortHash: 'abc123d',
|
||||
date: '2026-02-16T10:00:00.000Z',
|
||||
subject: 'feat: local commit',
|
||||
author: 'Local Dev',
|
||||
syncStatus: 'local-only',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getFileHistory', () => {
|
||||
|
||||
Reference in New Issue
Block a user