diff --git a/src/__tests__/branchList.regression.test.ts b/src/__tests__/branchList.regression.test.ts index a62caf6..c38e9a9 100644 --- a/src/__tests__/branchList.regression.test.ts +++ b/src/__tests__/branchList.regression.test.ts @@ -46,7 +46,7 @@ function setupRepoForIssue167(options?: { disableReflog?: boolean; firstBranchCo writeAndCommit(repoDir, 'develop-takt.txt', 'develop takt\n', 'takt: old instruction on develop'); writeAndCommit(repoDir, 'develop-b.txt', 'develop b\n', 'develop commit B'); - const taktBranch = 'takt/#167/fix-original-instruction'; + const taktBranch = 'takt/167/fix-original-instruction'; runGit(repoDir, ['checkout', '-b', taktBranch]); const firstBranchCommitMessage = options?.firstBranchCommitMessage ?? 'takt: github-issue-167-fix-original-instruction'; writeAndCommit(repoDir, 'task-1.txt', 'task1\n', firstBranchCommitMessage); diff --git a/src/__tests__/clone.test.ts b/src/__tests__/clone.test.ts index 2b293da..11a5e79 100644 --- a/src/__tests__/clone.test.ts +++ b/src/__tests__/clone.test.ts @@ -207,7 +207,7 @@ describe('branch and worktree path formatting with issue numbers', () => { }); } - it('should format branch as takt/#{issue}/{slug} when issue number is provided', () => { + it('should format branch as takt/{issue}/{slug} when issue number is provided', () => { // Given: issue number 99 with slug setupMockForPathTest(); @@ -219,7 +219,7 @@ describe('branch and worktree path formatting with issue numbers', () => { }); // Then: branch should use issue format - expect(result.branch).toBe('takt/#99/fix-login-timeout'); + expect(result.branch).toBe('takt/99/fix-login-timeout'); }); it('should format branch as takt/{timestamp}-{slug} when no issue number', () => { diff --git a/src/infra/task/clone.ts b/src/infra/task/clone.ts index 098c0d0..f424707 100644 --- a/src/infra/task/clone.ts +++ b/src/infra/task/clone.ts @@ -77,7 +77,7 @@ export class CloneManager { const slug = slugify(options.taskSlug); if (options.issueNumber !== undefined && slug) { - return `takt/#${options.issueNumber}/${slug}`; + return `takt/${options.issueNumber}/${slug}`; } const timestamp = CloneManager.generateTimestamp(); @@ -124,13 +124,24 @@ export class CloneManager { return projectDir; } - /** Clone a repository and remove origin to isolate from the main repo */ - private static cloneAndIsolate(projectDir: string, clonePath: string): void { + /** Clone a repository and remove origin to isolate from the main repo. + * When `branch` is specified, `--branch` is passed to `git clone` so the + * branch is checked out as a local branch *before* origin is removed. + * Without this, non-default branches are lost when `git remote remove origin` + * deletes the remote-tracking refs. + */ + private static cloneAndIsolate(projectDir: string, clonePath: string, branch?: string): void { const referenceRepo = CloneManager.resolveMainRepo(projectDir); fs.mkdirSync(path.dirname(clonePath), { recursive: true }); - execFileSync('git', ['clone', '--reference', referenceRepo, '--dissociate', projectDir, clonePath], { + const cloneArgs = ['clone', '--reference', referenceRepo, '--dissociate']; + if (branch) { + cloneArgs.push('--branch', branch); + } + cloneArgs.push(projectDir, clonePath); + + execFileSync('git', cloneArgs, { cwd: projectDir, stdio: 'pipe', }); @@ -174,11 +185,10 @@ export class CloneManager { log.info('Creating shared clone', { path: clonePath, branch }); - CloneManager.cloneAndIsolate(projectDir, clonePath); - - if (CloneManager.branchExists(clonePath, branch)) { - execFileSync('git', ['checkout', branch], { cwd: clonePath, stdio: 'pipe' }); + if (CloneManager.branchExists(projectDir, branch)) { + CloneManager.cloneAndIsolate(projectDir, clonePath, branch); } else { + CloneManager.cloneAndIsolate(projectDir, clonePath); execFileSync('git', ['checkout', '-b', branch], { cwd: clonePath, stdio: 'pipe' }); } @@ -195,8 +205,7 @@ export class CloneManager { log.info('Creating temp clone for branch', { path: clonePath, branch }); - CloneManager.cloneAndIsolate(projectDir, clonePath); - execFileSync('git', ['checkout', branch], { cwd: clonePath, stdio: 'pipe' }); + CloneManager.cloneAndIsolate(projectDir, clonePath, branch); this.saveCloneMeta(projectDir, branch, clonePath); log.info('Temp clone created', { path: clonePath, branch });