From 524f9170f0709116371ff764bbc3ddc58d62624a Mon Sep 17 00:00:00 2001 From: Chris Scott <99081550+chriswritescode-dev@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:38:11 +0000 Subject: [PATCH] fix: filter source control commits by branch --- backend/src/routes/repo-git.ts | 3 +- backend/src/services/git/GitService.ts | 4 +- backend/test/services/git/GitService.test.ts | 54 +++++++++++++++++++ frontend/src/api/git.ts | 10 ++-- .../components/source-control/CommitsTab.tsx | 5 +- .../source-control/SourceControlPanel.tsx | 2 +- 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/backend/src/routes/repo-git.ts b/backend/src/routes/repo-git.ts index 8bf46180f..b85be5abf 100644 --- a/backend/src/routes/repo-git.ts +++ b/backend/src/routes/repo-git.ts @@ -407,7 +407,8 @@ export function createRepoGitRoutes(database: Database, gitAuthService: GitAuthS } const limit = parseInt(c.req.query('limit') || '10', 10) - const commits = await git.getLog(id, database, limit) + const branch = c.req.query('branch') || undefined + const commits = await git.getLog(id, database, limit, branch) return c.json({ commits }) } catch (error: unknown) { diff --git a/backend/src/services/git/GitService.ts b/backend/src/services/git/GitService.ts index 444bd39af..f58e7fe5b 100644 --- a/backend/src/services/git/GitService.ts +++ b/backend/src/services/git/GitService.ts @@ -84,7 +84,7 @@ export class GitService { return this.getFileDiff(repoId, filePath, database, { includeStaged }) } - async getLog(repoId: number, database: Database, limit: number = 10): Promise { + async getLog(repoId: number, database: Database, limit: number = 10, branch?: string): Promise { try { const repo = getRepoById(database, repoId) if (!repo) { @@ -97,7 +97,7 @@ export class GitService { '-C', repoPath, 'log', - `--all`, + branch?.trim() || 'HEAD', `-n`, String(limit), '--format=%H|%an|%ae|%at|%s' diff --git a/backend/test/services/git/GitService.test.ts b/backend/test/services/git/GitService.test.ts index 4ff27237f..2d00012ac 100644 --- a/backend/test/services/git/GitService.test.ts +++ b/backend/test/services/git/GitService.test.ts @@ -436,6 +436,16 @@ describe('GitService', () => { const result = await service.getLog(1, database, 10) expect(getRepoByIdMock).toHaveBeenCalledWith(database, 1) + expect(executeCommandMock).toHaveBeenNthCalledWith(1, [ + 'git', + '-C', + '/path/to/repo', + 'log', + 'HEAD', + '-n', + '10', + '--format=%H|%an|%ae|%at|%s' + ], { env: {} }) expect(result).toHaveLength(2) expect(result[0]).toEqual({ hash: 'abc123', @@ -467,6 +477,50 @@ describe('GitService', () => { expect(result).toEqual([]) }) + + it('uses the requested branch when provided', async () => { + const mockRepo = { + id: 1, + fullPath: '/path/to/repo', + } + getRepoByIdMock.mockReturnValue(mockRepo as any) + executeCommandMock.mockResolvedValueOnce('').mockResolvedValueOnce('') + + await service.getLog(1, database, 10, 'feature/test') + + expect(executeCommandMock).toHaveBeenNthCalledWith(1, [ + 'git', + '-C', + '/path/to/repo', + 'log', + 'feature/test', + '-n', + '10', + '--format=%H|%an|%ae|%at|%s' + ], { env: {} }) + }) + + it('falls back to HEAD for blank branch values', async () => { + const mockRepo = { + id: 1, + fullPath: '/path/to/repo', + } + getRepoByIdMock.mockReturnValue(mockRepo as any) + executeCommandMock.mockResolvedValueOnce('').mockResolvedValueOnce('') + + await service.getLog(1, database, 10, ' ') + + expect(executeCommandMock).toHaveBeenNthCalledWith(1, [ + 'git', + '-C', + '/path/to/repo', + 'log', + 'HEAD', + '-n', + '10', + '--format=%H|%an|%ae|%at|%s' + ], { env: {} }) + }) }) describe('getCommit', () => { diff --git a/frontend/src/api/git.ts b/frontend/src/api/git.ts index 66ec61d37..d6afc2d83 100644 --- a/frontend/src/api/git.ts +++ b/frontend/src/api/git.ts @@ -35,9 +35,9 @@ export async function fetchGitDiff(repoId: number, path: string): Promise<{ diff return { diff: data } } -export async function fetchGitLog(repoId: number, limit?: number): Promise<{ commits: GitCommit[] }> { +export async function fetchGitLog(repoId: number, limit?: number, branch?: string): Promise<{ commits: GitCommit[] }> { return fetchWrapper(`${API_BASE_URL}/api/repos/${repoId}/git/log`, { - params: { limit }, + params: { limit, branch }, }) } @@ -130,10 +130,10 @@ export function useCommitFileDiff(repoId: number | undefined, commitHash: string }) } -export function useGitLog(repoId: number | undefined, limit?: number) { +export function useGitLog(repoId: number | undefined, limit?: number, branch?: string) { return useQuery({ - queryKey: ['gitLog', repoId, limit], - queryFn: () => repoId ? fetchGitLog(repoId, limit) : Promise.reject(new Error('No repo ID')), + queryKey: ['gitLog', repoId, limit, branch], + queryFn: () => repoId ? fetchGitLog(repoId, limit, branch) : Promise.reject(new Error('No repo ID')), enabled: !!repoId, }) } diff --git a/frontend/src/components/source-control/CommitsTab.tsx b/frontend/src/components/source-control/CommitsTab.tsx index a4b765b07..eb231f229 100644 --- a/frontend/src/components/source-control/CommitsTab.tsx +++ b/frontend/src/components/source-control/CommitsTab.tsx @@ -5,6 +5,7 @@ import { GIT_UI_COLORS } from '@/lib/git-status-styles' interface CommitsTabProps { repoId: number + branch: string onSelectCommit?: (hash: string) => void } @@ -28,8 +29,8 @@ function formatRelativeTime(timestamp: string): string { return `${diffMonths}mo ago` } -export function CommitsTab({ repoId, onSelectCommit }: CommitsTabProps) { - const { data, isLoading, error } = useGitLog(repoId, 50) +export function CommitsTab({ repoId, branch, onSelectCommit }: CommitsTabProps) { + const { data, isLoading, error } = useGitLog(repoId, 50, branch) if (isLoading) { return ( diff --git a/frontend/src/components/source-control/SourceControlPanel.tsx b/frontend/src/components/source-control/SourceControlPanel.tsx index 7da7c9955..6451da85b 100644 --- a/frontend/src/components/source-control/SourceControlPanel.tsx +++ b/frontend/src/components/source-control/SourceControlPanel.tsx @@ -230,7 +230,7 @@ export function SourceControlPanel({ /> )} {activeTab === 'commits' && currentView === 'default' && ( - + )} {activeTab === 'branches' && currentView === 'default' && (