From 444b1cb40389de4cce557fb070fdfbe6afbbcc82 Mon Sep 17 00:00:00 2001 From: Osvaldo Ortega <48293249+osortega@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:39:12 -0700 Subject: [PATCH] Command to create worktrees with defaults (#268398) * Command to create worktrees with defaults * Update extensions/git/src/commands.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- extensions/git/package.json | 6 +++ extensions/git/src/commands.ts | 79 ++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) diff --git a/extensions/git/package.json b/extensions/git/package.json index 87e7dcae439..6f417a43e75 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -573,6 +573,12 @@ "category": "Git", "enablement": "!operationInProgress" }, + { + "command": "git.createWorktreeWithDefaults", + "title": "Create Worktree With Defaults", + "category": "Git", + "enablement": "!operationInProgress" + }, { "command": "git.deleteWorktree", "title": "%command.deleteWorktree%", diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 7054410ee05..d620679eeb6 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -3507,6 +3507,85 @@ export class CommandCenter { }); } + @command('git.createWorktreeWithDefaults', { repository: true, repositoryFilter: ['repository'] }) + async createWorktreeWithDefaults( + repository: Repository, + commitish: string = 'HEAD' + ): Promise { + const config = workspace.getConfiguration('git'); + const branchPrefix = config.get('branchPrefix', ''); + + // Generate branch name if not provided + let branch = await this.generateRandomBranchName(repository, '-'); + if (!branch) { + // Fallback to timestamp-based name if random generation fails + const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19); + branch = `${branchPrefix}worktree-${timestamp}`; + } + + // Ensure branch name starts with prefix if configured + if (branchPrefix && !branch.startsWith(branchPrefix)) { + branch = branchPrefix + branch; + } + + // Create worktree name from branch name + const worktreeName = branch.startsWith(branchPrefix) + ? branch.substring(branchPrefix.length).replace(/\//g, '-') + : branch.replace(/\//g, '-'); + + // Determine default worktree path + const defaultWorktreeRoot = this.globalState.get(`${CommandCenter.WORKTREE_ROOT_KEY}:${repository.root}`); + const defaultWorktreePath = defaultWorktreeRoot + ? path.join(defaultWorktreeRoot, worktreeName) + : path.join(path.dirname(repository.root), `${path.basename(repository.root)}.worktrees`, worktreeName); + + // Check if worktree already exists at this path + const existingWorktree = repository.worktrees.find(worktree => + pathEquals(path.normalize(worktree.path), path.normalize(defaultWorktreePath)) + ); + + if (existingWorktree) { + // Generate unique path by appending a number + let counter = 1; + let uniquePath = `${defaultWorktreePath}-${counter}`; + while (repository.worktrees.some(wt => pathEquals(path.normalize(wt.path), path.normalize(uniquePath)))) { + counter++; + uniquePath = `${defaultWorktreePath}-${counter}`; + } + const finalWorktreePath = uniquePath; + + try { + await repository.addWorktree({ path: finalWorktreePath, branch, commitish }); + + // Update worktree root in global state + const worktreeRoot = path.dirname(finalWorktreePath); + if (worktreeRoot !== defaultWorktreeRoot) { + this.globalState.update(`${CommandCenter.WORKTREE_ROOT_KEY}:${repository.root}`, worktreeRoot); + } + + return finalWorktreePath; + } catch (err) { + // Return undefined on failure + return undefined; + } + } + + try { + await repository.addWorktree({ path: defaultWorktreePath, branch, commitish }); + + // Update worktree root in global state + const worktreeRoot = path.dirname(defaultWorktreePath); + if (worktreeRoot !== defaultWorktreeRoot) { + this.globalState.update(`${CommandCenter.WORKTREE_ROOT_KEY}:${repository.root}`, worktreeRoot); + } + + return defaultWorktreePath; + } catch (err) { + // Return undefined on failure + return undefined; + } + } + @command('git.createWorktree') async createWorktree(repository: any): Promise { repository = this.model.getRepository(repository);