From 09c7167a49e91465ae427d30d32cdfe316236932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=A8=8B=E5=BA=8F=E5=91=98=E9=98=BF=E6=B1=9F=28Relakkes?= =?UTF-8?q?=29?= Date: Thu, 21 May 2026 17:21:02 +0800 Subject: [PATCH] fix: prevent worktree sessions showing source branch Desktop git-info preserved the launch branch before checking the active worktree cwd, so materialized isolated worktree sessions could keep showing the source branch instead of the branch Git had checked out in the worktree. The API now switches to the real cwd branch only once the session has actually entered its planned worktree, while direct branch launches still keep their stable launch branch. Constraint: Direct branch launches still need stable launch metadata when the source checkout later changes. Rejected: Always prefer git rev-parse output | would regress direct launch sessions that intentionally show the selected branch. Confidence: high Scope-risk: narrow Tested: bun test src/server/__tests__/sessions.test.ts -t "git-info" Tested: /tmp/cc-haha-issue-539-verify API reproduction returned the worktree branch Tested: bun run check:server --- src/server/__tests__/sessions.test.ts | 6 +++--- src/server/api/sessions.ts | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/server/__tests__/sessions.test.ts b/src/server/__tests__/sessions.test.ts index 8b341590..cfb77ba1 100644 --- a/src/server/__tests__/sessions.test.ts +++ b/src/server/__tests__/sessions.test.ts @@ -2022,7 +2022,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe('main') + expect(body.branch).toBe(repository!.worktreeBranch) expect(body.workDir).toBe(activeWorktree) expect(body.worktree).toEqual({ enabled: true, @@ -2067,7 +2067,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe('main') + expect(body.branch).toBe('worktree-desktop-main-12345678') expect(body.workDir).toBe(activeWorktree) expect(body.worktree).toEqual({ enabled: true, @@ -2121,7 +2121,7 @@ describe('Sessions API', () => { branch: string | null } | null } - expect(body.branch).toBe('main') + expect(body.branch).toBe('worktree-desktop-main-12345678') expect(body.worktree).toMatchObject({ path: activeWorktree, plannedPath: activeWorktree, diff --git a/src/server/api/sessions.ts b/src/server/api/sessions.ts index 51d9e375..c1bff8c9 100644 --- a/src/server/api/sessions.ts +++ b/src/server/api/sessions.ts @@ -15,6 +15,7 @@ * PATCH /api/sessions/:id — 重命名会话 */ +import * as path from 'node:path' import { sessionService } from '../services/sessionService.js' import { conversationService } from '../services/conversationService.js' import { ApiError, errorResponse } from '../middleware/errorHandler.js' @@ -622,6 +623,11 @@ function chooseRicherUsage( : currentUsage } +function sameResolvedPath(left: string | null | undefined, right: string | null | undefined): boolean { + if (!left || !right) return false + return path.resolve(left) === path.resolve(right) +} + async function getGitInfo(sessionId: string): Promise { const workDir = conversationService.getSessionWorkDir(sessionId) || await sessionService.getSessionWorkDir(sessionId) if (!workDir) { @@ -653,7 +659,14 @@ async function getGitInfo(sessionId: string): Promise { stderr: 'pipe', }) const branchText = await new Response(branchProc.stdout).text() - const branch = sessionBranch || branchText.trim() + const gitBranch = branchText.trim() || null + const materializedWorktree = !!worktree && ( + sameResolvedPath(workDir, worktree.path) || + sameResolvedPath(workDir, worktree.plannedPath) + ) + const branch = materializedWorktree + ? (gitBranch || worktree.branch || sessionBranch) + : (sessionBranch || gitBranch) // Get repo name from remote or directory let repoName = ''