diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 690947f..8908759 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -120,5 +120,6 @@ "Please input branch name": "请输入分支名称", "Delete branch": "删除分支", "The branch {0} based on {1} will be deleted": "将删除基于 {1} 的分支 {0}", - "Failed to delete branch ( {0} ), {1}": "删除分支 ( {0} ) 失败, {1}" + "Failed to delete branch ( {0} ), {1}": "删除分支 ( {0} ) 失败, {1}", + "Failed to copy files: {error}": "复制文件失败: {error}" } diff --git a/package.json b/package.json index 4888efa..5717abe 100644 --- a/package.json +++ b/package.json @@ -762,6 +762,29 @@ "type": "boolean", "default": false, "description": "%config.promptDeleteBranchAfterWorktreeDeletion.description%" + }, + "git-worktree-manager.worktreeCopyPatterns": { + "type": "array", + "default": [ + ".env", + ".vscode/**", + "*.local" + ], + "markdownDescription": "%config.worktreeCopyPatterns.description%" + }, + "git-worktree-manager.worktreeCopyIgnores": { + "type": "array", + "default": [ + "**/node_modules/**", + "**/dist/**", + "**/.git/**", + "**/.svn/**", + "**/.hg/**", + "**/CVS/**", + "**/Thumbs.db/**", + "**/.DS_Store" + ], + "markdownDescription": "%config.worktreeCopyIgnores.description%" } } }, diff --git a/package.nls.json b/package.nls.json index e2c585d..5b03e98 100644 --- a/package.nls.json +++ b/package.nls.json @@ -81,5 +81,7 @@ "config.worktreePick.showDeleteWorktree.description": "Show the \"Delete Worktree\" button on the results of \"Find Worktree\"", "config.branchPick.showDeleteBranch.description": "Show the \"Delete Branch\" button on the results of \"Pick Branch\"", "config.promptDeleteBranchAfterWorktreeDeletion.description": "Prompt to delete the branch previously associated with the worktree after its deletion", + "config.worktreeCopyPatterns.description": "Glob patterns for files to be copied when creating a new worktree, referring to [glob patterns](https://code.visualstudio.com/docs/editor/glob-patterns).", + "config.worktreeCopyIgnores.description": "Glob patterns for files to be excluded when copying files to a new worktree, referring to [glob patterns](https://code.visualstudio.com/docs/editor/glob-patterns).", "submenus.worktree-action": "Worktree Action" } diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 20c2cf2..f088047 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -81,5 +81,7 @@ "config.worktreePick.showDeleteWorktree.description": "在 \"查找 Worktree\" 列表中展示 \"删除 worktree\" 按钮", "config.branchPick.showDeleteBranch.description": "在 \"挑选分支\" 列表中展示 \"删除分支\" 按钮", "config.promptDeleteBranchAfterWorktreeDeletion.description": "在删除 worktree 之后,是否提示删除之前关联的分支", + "config.worktreeCopyPatterns.description": "创建新 worktree 时需要复制的文件匹配模式,参考[glob patterns介绍](https://juejin.cn/post/7474119575574855717)", + "config.worktreeCopyIgnores.description": "创建新 worktree 时需要排除的文件匹配模式,参考[glob patterns介绍](https://juejin.cn/post/7474119575574855717)", "submenus.worktree-action": "worktree 操作" } diff --git a/src/core/command/createWorktreeFromInfo.ts b/src/core/command/createWorktreeFromInfo.ts index 9c17ebb..81bd3a5 100644 --- a/src/core/command/createWorktreeFromInfo.ts +++ b/src/core/command/createWorktreeFromInfo.ts @@ -1,14 +1,11 @@ import * as vscode from 'vscode'; import { addWorktree } from '@/core/git/addWorktree'; +import { getMainFolder } from '@/core/git/getMainFolder'; import { confirmModal } from '@/core/ui/modal'; +import { copyWorktreeFiles } from '@/core/util/copyWorktreeFiles'; +import type { ICreateWorktreeInfo } from '@/types'; -export const createWorktreeFromInfo = async (info: { - folderPath: string; - name: string; - label: string; - isBranch: boolean; - cwd?: string; -}) => { +export async function createWorktreeFromInfo(info: ICreateWorktreeInfo) { const { folderPath, name, label, isBranch, cwd } = info; let confirmCreate = await confirmModal( vscode.l10n.t('Create worktree'), @@ -21,6 +18,13 @@ export const createWorktreeFromInfo = async (info: { if (!created) { return; } + + const mainFolder = await getMainFolder(folderPath); + // Copy files after worktree creation is successful + if (mainFolder) { + await copyWorktreeFiles(mainFolder, folderPath); + } + let confirmOpen = await confirmModal( vscode.l10n.t('Open folder'), vscode.l10n.t('Whether to open the new worktree in a new window?'), @@ -32,4 +36,4 @@ export const createWorktreeFromInfo = async (info: { vscode.commands.executeCommand('vscode.openFolder', folderUri, { forceNewWindow: true, }); -}; \ No newline at end of file +} diff --git a/src/core/config/setting.ts b/src/core/config/setting.ts index f71e890..12dee85 100644 --- a/src/core/config/setting.ts +++ b/src/core/config/setting.ts @@ -28,6 +28,8 @@ export class Config { static get(key: 'httpProxy', defaultValue: ''): string; static get(key: 'workspacePathFormat', defaultValue: '$BASE_NAME - $FULL_PATH'): string; static get(key: 'promptDeleteBranchAfterWorktreeDeletion', defaultValue: false): boolean; + static get(key: 'worktreeCopyPatterns', defaultValue: []): string[]; + static get(key: 'worktreeCopyIgnores', defaultValue: []): string[]; static get(key: string, defaultValue: T): T { return vscode.workspace.getConfiguration(APP_NAME).get(key, defaultValue); } diff --git a/src/core/util/copyWorktreeFiles.ts b/src/core/util/copyWorktreeFiles.ts new file mode 100644 index 0000000..51ebe63 --- /dev/null +++ b/src/core/util/copyWorktreeFiles.ts @@ -0,0 +1,39 @@ +import * as vscode from 'vscode'; +import path from 'path'; +import fs from 'fs/promises'; +import { pipeline } from 'stream/promises'; +import { createReadStream, createWriteStream } from 'fs'; +import { Config } from '@/core/config/setting'; + +export async function copyWorktreeFiles(sourceRepo: string, targetWorktree: string) { + try { + const patterns = Config.get('worktreeCopyPatterns', []); + const ignorePatterns = Config.get('worktreeCopyIgnores', []); + + if (patterns.length === 0) return; + + // Find matching files + const files = await vscode.workspace.findFiles( + new vscode.RelativePattern(sourceRepo, `{${patterns.join(',')}}`), + `{${ignorePatterns.join(',')}}`, + ); + + // Copy the found files + for (const file of files) { + const relativePath = path.relative(sourceRepo, file.fsPath); + const targetPath = path.join(targetWorktree, relativePath); + const targetDir = path.dirname(targetPath); + + // Ensure target directory exists + await fs.mkdir(targetDir, { recursive: true }); + + // Copy single file + await pipeline( + createReadStream(file.fsPath), + createWriteStream(targetPath) + ); + } + } catch (error: any) { + vscode.window.showErrorMessage(vscode.l10n.t('Failed to copy files: {error}', { error })); + } +} diff --git a/src/types.ts b/src/types.ts index d9a40ac..ba65ba4 100644 --- a/src/types.ts +++ b/src/types.ts @@ -134,3 +134,11 @@ export type IPickBranchParams = { showCreate: boolean; }; export type IPickBranch = (params: IPickBranchParams) => Promise; + +export interface ICreateWorktreeInfo { + folderPath: string; + name: string; + label: string; + isBranch: boolean; + cwd?: string; +}