@gitkraken/core-gitlens 0.25.0 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/dist/git/providers/operations.d.ts +15 -0
  3. package/dist/git/watching/worktreeSummary.d.ts +15 -3
  4. package/dist/git/watching/worktreeSummary.js +179 -31
  5. package/dist/git/watching/worktreeSummary.js.map +1 -1
  6. package/dist/git-cli/cliGitProvider.d.ts +16 -0
  7. package/dist/git-cli/cliGitProvider.js +31 -6
  8. package/dist/git-cli/cliGitProvider.js.map +1 -1
  9. package/dist/git-cli/exec/git.d.ts +2 -0
  10. package/dist/git-cli/exec/git.js +4 -0
  11. package/dist/git-cli/exec/git.js.map +1 -1
  12. package/dist/git-cli/exec/gitDirResolver.d.ts +26 -0
  13. package/dist/git-cli/exec/gitDirResolver.js +181 -0
  14. package/dist/git-cli/exec/gitDirResolver.js.map +1 -0
  15. package/dist/git-cli/exec/headState.js +3 -3
  16. package/dist/git-cli/exec/headState.js.map +1 -1
  17. package/dist/git-cli/exec/indexRefresh.d.ts +78 -0
  18. package/dist/git-cli/exec/indexRefresh.js +159 -0
  19. package/dist/git-cli/exec/indexRefresh.js.map +1 -0
  20. package/dist/git-cli/providers/config.d.ts +2 -0
  21. package/dist/git-cli/providers/config.js +22 -3
  22. package/dist/git-cli/providers/config.js.map +1 -1
  23. package/dist/git-cli/providers/maintenance.js +1 -1
  24. package/dist/git-cli/providers/operations.d.ts +4 -1
  25. package/dist/git-cli/providers/operations.js +33 -25
  26. package/dist/git-cli/providers/operations.js.map +1 -1
  27. package/dist/git-cli/providers/pausedOperations.d.ts +3 -1
  28. package/dist/git-cli/providers/pausedOperations.js +10 -7
  29. package/dist/git-cli/providers/pausedOperations.js.map +1 -1
  30. package/dist/git-cli/providers/refs.js +25 -1
  31. package/dist/git-cli/providers/refs.js.map +1 -1
  32. package/dist/git-cli/providers/staging.js +1 -1
  33. package/dist/git-cli/providers/stash.d.ts +3 -1
  34. package/dist/git-cli/providers/stash.js +8 -5
  35. package/dist/git-cli/providers/stash.js.map +1 -1
  36. package/dist/git-cli/providers/worktrees.d.ts +6 -1
  37. package/dist/git-cli/providers/worktrees.js +6 -2
  38. package/dist/git-cli/providers/worktrees.js.map +1 -1
  39. package/dist/git-cli/service.d.ts +2 -0
  40. package/dist/git-cli/service.js +2 -1
  41. package/dist/git-cli/service.js.map +1 -1
  42. package/dist/ipc/discovery.js +1 -1
  43. package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
  44. package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
  45. package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
  46. package/dist/plus/integrations/providers/azure/azure.js +1 -1
  47. package/dist/utils/env/node/exec.js +2 -2
  48. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"stash.js","names":[],"sources":["../../../../git-cli/src/providers/stash.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { StashApplyError, StashPushError } from '@gitlens/git/errors.js';\nimport type { GitStashCommit } from '@gitlens/git/models/commit.js';\nimport { GitCommit, GitCommitIdentity } from '@gitlens/git/models/commit.js';\nimport { GitFileChange } from '@gitlens/git/models/fileChange.js';\nimport type { GitFileStatus } from '@gitlens/git/models/fileStatus.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitStash } from '@gitlens/git/models/stash.js';\nimport type { GitUser } from '@gitlens/git/models/user.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitStashSubProvider, StashApplyResult } from '@gitlens/git/providers/stash.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { skip } from '@gitlens/utils/iterable.js';\nimport { normalizePath, splitPath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, joinUriPath, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { gitFeaturesByVersion } from '../exec/features.js';\nimport type { Git } from '../exec/git.js';\nimport { getGitCommandError, GitError, GitErrors, isRunHookFailure, maxGitCliLength } from '../exec/git.js';\nimport type { ParsedStash, ParsedStashWithFiles } from '../parsers/logParser.js';\nimport { getStashFilesOnlyLogParser, getStashLogParser } from '../parsers/logParser.js';\nimport { createCommitFileset } from './commitFilesetUtils.js';\n\n/** The one ref a stash write moves: a push, pop, drop or store changes `refs/stash` or its reflog, never another ref */\nconst stashRefs: readonly string[] = ['refs/stash'];\n\nexport class StashGitSubProvider implements GitStashSubProvider {\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t) {}\n\n\t@gate()\n\t@debug()\n\tasync applyStash(\n\t\trepoPath: string,\n\t\tstashNameOrSha: string,\n\t\toptions?: { deleteAfter?: boolean; index?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\tif (!stashNameOrSha) return { conflicted: false };\n\n\t\tconst args = ['stash', options?.deleteAfter ? 'pop' : 'apply'];\n\t\tif (options?.index) {\n\t\t\targs.push('--index');\n\t\t}\n\t\targs.push(stashNameOrSha);\n\t\treturn this.applyStashCore(repoPath, args, options?.deleteAfter ? 'stash-pop' : 'stash-apply', runOptions);\n\t}\n\n\tprivate async applyStashCore(\n\t\trepoPath: string,\n\t\targs: string[],\n\t\tconflictCommand: 'stash-apply' | 'stash-pop',\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\t// Only a clean pop is known to have moved `refs/stash`: a conflicted one keeps the entry\n\t\tlet dropped = false;\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\t\t\tdropped = conflictCommand === 'stash-pop';\n\t\t\treturn { conflicted: false };\n\t\t} catch (ex) {\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tconst msg: string = ex.message ?? '';\n\t\t\t\tif (\n\t\t\t\t\t(msg.includes('Auto-merging') && msg.includes('CONFLICT')) ||\n\t\t\t\t\t(ex instanceof GitError &&\n\t\t\t\t\t\t((ex.stdout?.includes('Auto-merging') && ex.stdout.includes('CONFLICT')) ||\n\t\t\t\t\t\t\tex.stdout?.includes('needs merge')))\n\t\t\t\t) {\n\t\t\t\t\tthis.context.hooks?.operations?.onConflicted?.(conflictCommand);\n\t\t\t\t\treturn { conflicted: true };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-apply',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashApplyError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A conflicted, failed or cancelled apply may already have changed the stash list or working tree\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\tif (dropped) {\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t\t\t} else {\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync createStash(repoPath: string, message?: string): Promise<string | undefined> {\n\t\tconst args = ['stash', 'create'];\n\t\tif (message) {\n\t\t\targs.push(message);\n\t\t}\n\n\t\tconst result = await this.git.run({ cwd: repoPath }, ...args);\n\t\treturn result.stdout.trim() || undefined;\n\t}\n\n\t@debug({ quiet: true })\n\tasync getStash(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tincludeFiles?: boolean;\n\t\t\treachableFrom?: string;\n\t\t\tsimilarityThreshold?: number | null;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStash | undefined> {\n\t\tif (repoPath == null) return undefined;\n\n\t\t// Resolve options against config up front so the cache key reflects the actual values used\n\t\t// to produce the cached payload — undefined inputs aren't conflated across config changes.\n\t\tconst cfg = this.context.config;\n\t\tconst includeFiles = options?.includeFiles ?? cfg?.commits.includeFileDetails?.(repoPath) ?? true;\n\t\tconst similarityThreshold = includeFiles\n\t\t\t? (options?.similarityThreshold ?? cfg?.commits.similarityThreshold ?? null)\n\t\t\t: null;\n\t\tconst reachableFrom = options?.reachableFrom;\n\n\t\t// Cache only the unfiltered stash list; reachability projection runs below by testing each\n\t\t// distinct stash parent against `reachableFrom` directly, so re-projecting is cheap\n\t\tconst cacheKey = `f${includeFiles ? 1 : 0}|s${similarityThreshold ?? ''}`;\n\n\t\tconst stash = await this.cache.getStash(\n\t\t\trepoPath,\n\t\t\tcacheKey,\n\t\t\tasync (commonPath, _cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst parser = getStashLogParser(includeFiles);\n\t\t\t\tconst args = [...parser.arguments];\n\n\t\t\t\tif (includeFiles) {\n\t\t\t\t\targs.push(`-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`);\n\t\t\t\t}\n\n\t\t\t\tconst result = await this.git.run({ cwd: repoPath, cancellation: signal }, 'stash', 'list', ...args);\n\n\t\t\t\tconst currentUser = await this.provider.config.getCurrentUser(repoPath);\n\n\t\t\t\tconst stashes = new Map<string, GitStashCommit>();\n\t\t\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\t\t\tstashes.set(s.sha, createStash(s, commonPath, currentUser));\n\t\t\t\t}\n\n\t\t\t\treturn { repoPath: commonPath, stashes: stashes };\n\t\t\t},\n\t\t\t{ cancellation: cancellation },\n\t\t);\n\n\t\tif (stash == null || !reachableFrom || !stash.stashes.size) return stash;\n\n\t\t// Copy because the cached `stash.stashes` map is shared and must not be mutated.\n\t\tconst stashes = new Map(stash.stashes);\n\n\t\tconst reachableStashes = new Set<string>();\n\n\t\t// Metadata pass: a stash belongs on `reachableFrom` iff git's auto-prepended\n\t\t// `On <branch>: …` (or `WIP on <branch>: …`) prefix in the stash commit subject names\n\t\t// this branch. `stashOnRef` is parsed from %s in createStash, so this covers autostashes\n\t\t// and custom-reflog stashes too.\n\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\tif (s.stashOnRef === reachableFrom) {\n\t\t\t\treachableStashes.add(sha);\n\t\t\t}\n\t\t}\n\n\t\t// Transitive pass for the rare detached-HEAD-on-stash chain (stash B created while HEAD\n\t\t// pointed at stash A). Such stashes have no `stashOnRef`, but if their parent is a stash\n\t\t// already marked reachable they should follow.\n\t\tlet changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\t\tif (!reachableStashes.has(sha) && s.parents.some(p => reachableStashes.has(p))) {\n\t\t\t\t\treachableStashes.add(sha);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (changed);\n\n\t\tfor (const [sha] of stash.stashes) {\n\t\t\tif (!reachableStashes.has(sha)) {\n\t\t\t\tstashes.delete(sha);\n\t\t\t}\n\t\t}\n\n\t\treturn { ...stash, stashes: stashes };\n\t}\n\n\t@debug({ quiet: true })\n\tasync getStashCommitFiles(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[]> {\n\t\tconst [stashFilesResult, stashUntrackedFilesResult] = await Promise.allSettled([\n\t\t\t// Don't include untracked files here, because we won't be able to tell them apart from added (and we need the untracked status)\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: false, ...options }, cancellation),\n\t\t\t// Check for any untracked files -- since git doesn't return them via `git stash list` :(\n\t\t\t// See https://stackoverflow.com/questions/12681529/\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: 'only', ...options }, cancellation),\n\t\t]);\n\n\t\tlet files = getSettledValue(stashFilesResult);\n\t\tconst untrackedFiles = getSettledValue(stashUntrackedFilesResult);\n\n\t\tif (files?.length && untrackedFiles?.length) {\n\t\t\tfiles.push(...untrackedFiles);\n\t\t} else {\n\t\t\tfiles = files ?? untrackedFiles;\n\t\t}\n\n\t\treturn files ?? [];\n\t}\n\n\tprivate async getStashCommitFilesCore(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null; untracked?: boolean | 'only' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[] | undefined> {\n\t\tconst args = [];\n\t\tif (options?.untracked) {\n\t\t\targs.push(options?.untracked === 'only' ? '--only-untracked' : '--include-untracked');\n\t\t}\n\n\t\tconst similarityThreshold = options?.similarityThreshold ?? this.context.config?.commits.similarityThreshold;\n\t\tif (similarityThreshold != null) {\n\t\t\targs.push(`-M${similarityThreshold}%`);\n\t\t}\n\n\t\tconst parser = getStashFilesOnlyLogParser();\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'stash',\n\t\t\t'show',\n\t\t\t...args,\n\t\t\t...parser.arguments,\n\t\t\tref,\n\t\t);\n\n\t\tconst repoUri = fileUri(normalizePath(repoPath));\n\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\treturn (\n\t\t\t\ts.files?.map(\n\t\t\t\t\tf =>\n\t\t\t\t\t\tnew GitFileChange(\n\t\t\t\t\t\t\trepoPath,\n\t\t\t\t\t\t\tf.path,\n\t\t\t\t\t\t\t(options?.untracked === 'only'\n\t\t\t\t\t\t\t\t? GitFileWorkingTreeStatus.Untracked\n\t\t\t\t\t\t\t\t: f.status) as GitFileStatus,\n\t\t\t\t\t\t\tjoinUriPath(repoUri, normalizePath(f.path)),\n\t\t\t\t\t\t\tf.originalPath,\n\t\t\t\t\t\t\tf.originalPath != null ? joinUriPath(repoUri, normalizePath(f.originalPath)) : undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.additions || f.deletions\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tadditions: f.additions ?? 0,\n\t\t\t\t\t\t\t\t\t\tdeletions: f.deletions ?? 0,\n\t\t\t\t\t\t\t\t\t\tchanges: 0,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.mode,\n\t\t\t\t\t\t),\n\t\t\t\t) ?? []\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t@debug()\n\tasync deleteStash(repoPath: string, stashName: string, sha?: string): Promise<void> {\n\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: true });\n\t}\n\n\t// Keyed without `options`, so a delete and a rename of the same stash share one drop: a second drop would take\n\t// the stash that moved up into its place\n\t@gate((rp, name, sha) => `${rp}\\0${name}\\0${sha ?? ''}`)\n\tprivate async deleteStashCore(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string | undefined,\n\t\toptions: { announce: boolean; verified?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (!stashName) return undefined;\n\n\t\tif (!options.verified) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.git.run({ cwd: repoPath }, 'stash', 'drop', stashName);\n\t\t} finally {\n\t\t\tif (options.announce) {\n\t\t\t\tthis.announceStashChanged(repoPath);\n\t\t\t}\n\t\t}\n\t\treturn result.stdout;\n\t}\n\n\tprivate async verifyStashSha(repoPath: string, stashName: string, sha: string | undefined): Promise<void> {\n\t\tif (!sha) return;\n\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, errors: 'ignore' },\n\t\t\t'show',\n\t\t\t'--format=%H',\n\t\t\t'--no-patch',\n\t\t\tstashName,\n\t\t);\n\t\tif (result.stdout.trim() !== sha) {\n\t\t\tthrow new Error(l10n.t('Unable to delete stash; mismatch with stash number'));\n\t\t}\n\t}\n\n\t@debug()\n\tasync renameStash(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string,\n\t\tmessage: string,\n\t\tstashOnRef?: string,\n\t): Promise<void> {\n\t\tif (stashName) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\t// The drop and the store announce once, after both ran, even if the store fails\n\t\ttry {\n\t\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: false, verified: true });\n\t\t\tawait this.git.run(\n\t\t\t\t{ cwd: repoPath },\n\t\t\t\t'stash',\n\t\t\t\t'store',\n\t\t\t\t'-m',\n\t\t\t\tstashOnRef ? `On ${stashOnRef}: ${message}` : message,\n\t\t\t\tsha,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug({ args: (repoPath, message, paths) => ({ repoPath: repoPath, message: message, paths: paths?.length }) })\n\tasync saveStash(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\tpathsOrUris?: (string | Uri)[],\n\t\toptions?: { includeUntracked?: boolean; keepIndex?: boolean; onlyStaged?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris?.map(toFsPath);\n\t\tif (!paths?.length) {\n\t\t\tawait this.stashPushCore(repoPath, message, options, runOptions);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.git.ensureSupports('git:stash:push:pathspecs', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Stashing individual files requires a newer version of Git (>= {0}) than is currently installed ({1}). Please retry by stashing everything or install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathspecs = paths.map(p => `./${splitPath(p, repoPath)[0]}`);\n\n\t\tlet stdin = await this.git.supports('git:stash:push:stdin');\n\t\tif (stdin && options?.onlyStaged && paths.length) {\n\t\t\t// Since Git doesn't support --staged with --pathspec-from-file try to pass them in directly\n\t\t\tstdin = false;\n\t\t}\n\n\t\t// If we don't support stdin, then error out if we are over the maximum allowed git cli length\n\t\tif (!stdin && countStringLength(pathspecs) > maxGitCliLength) {\n\t\t\tawait this.git.ensureSupports('git:stash:push:stdin', (requiredVersion, installedVersion) =>\n\t\t\t\tl10n.t(\n\t\t\t\t\t'Stashing so many files ({0}) at once requires a newer version of Git (>= {1}) than is currently installed ({2}). Please retry by stashing fewer files or install a more recent version of Git and try again.',\n\t\t\t\t\tpathspecs.length,\n\t\t\t\t\trequiredVersion,\n\t\t\t\t\tinstalledVersion,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait this.stashPushCore(\n\t\t\trepoPath,\n\t\t\tmessage,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tpathspecs: pathspecs,\n\t\t\t\tstdin: stdin,\n\t\t\t},\n\t\t\trunOptions,\n\t\t);\n\t}\n\n\tprivate async stashPushCore(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\toptions?: {\n\t\t\tincludeUntracked?: boolean;\n\t\t\tkeepIndex?: boolean;\n\t\t\tonlyStaged?: boolean;\n\t\t\tpathspecs?: string[];\n\t\t\tstdin?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst params = ['stash', 'push'];\n\n\t\tif ((options?.includeUntracked || options?.pathspecs?.length) && !options?.onlyStaged) {\n\t\t\tparams.push('--include-untracked');\n\t\t}\n\n\t\t// `git stash push --keep-index --include-untracked -- <pathspec>` hits a bug in git when the\n\t\t// pathspec names an untracked file: the restoring checkout can't match an untracked path in the\n\t\t// index tree, so it fails and the staged changes are lost.\n\t\t//\n\t\t// $ mkdir stash-test && cd stash-test && git init\n\t\t// $ echo a > a.txt\n\t\t// $ git add a.txt\n\t\t// $ git commit -m init\n\t\t// $ echo b > b.txt\n\t\t// $ git stash push --keep-index --include-untracked -- b.txt\n\t\t// Saved working directory and index state WIP on main: 8a280fe init\n\t\t// error: pathspec ':(prefix:0)b.txt' did not match any file(s) known to git\n\t\t//\n\t\t// Only suppress --keep-index for that case — when the selection actually includes untracked\n\t\t// files (`includeUntracked`) AND we're stashing by pathspec. Keying off `includeUntracked` (the\n\t\t// caller's intent) rather than the `--include-untracked` flag is deliberate: we add\n\t\t// `--include-untracked` to every pathspec push above as a safety net, but a tracked-only\n\t\t// selection can — and must — still keep the index intact.\n\t\tif (options?.keepIndex && !(options?.includeUntracked && options?.pathspecs?.length)) {\n\t\t\tparams.push('--keep-index');\n\t\t}\n\n\t\tif (options?.onlyStaged) {\n\t\t\tif (await this.git.supports('git:stash:push:staged')) {\n\t\t\t\tparams.push('--staged');\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tl10n.t(\n\t\t\t\t\t\t'Git version {0} or higher is required for --staged',\n\t\t\t\t\t\tString(gitFeaturesByVersion.get('git:stash:push:staged')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (message) {\n\t\t\tparams.push('-m', message);\n\t\t}\n\n\t\tlet stdin;\n\t\tif (options?.pathspecs?.length) {\n\t\t\tif (options.stdin) {\n\t\t\t\tstdin = options.pathspecs.join('\\0');\n\t\t\t\tparams.push('--pathspec-from-file=-', '--pathspec-file-nul', '--');\n\t\t\t} else {\n\t\t\t\tparams.push('--', ...options.pathspecs);\n\t\t\t}\n\t\t} else {\n\t\t\tparams.push('--');\n\t\t}\n\n\t\tlet nothingToSave = false;\n\t\ttry {\n\t\t\tconst result = await this.git.run({ cwd: repoPath, ...runOptions, stdin: stdin }, ...params);\n\t\t\tif (GitErrors.stashNothingToSave.test(result.stdout)) {\n\t\t\t\tnothingToSave = true;\n\t\t\t\tthrow new StashPushError({\n\t\t\t\t\treason: 'nothingToSave',\n\t\t\t\t\tgitCommand: { repoPath: repoPath, args: params },\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof StashPushError || isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-push',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashPushError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: params } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled push may already have stashed, and reset the working tree; one with nothing to\n\t\t\t// save changed nothing\n\t\t\tif (!nothingToSave) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync saveSnapshot(repoPath: string, message?: string): Promise<void> {\n\t\tconst result = await this.git.run({ cwd: repoPath }, 'stash', 'create');\n\t\tconst id = result.stdout.trim() || undefined;\n\t\tif (id == null) return;\n\n\t\tconst args = [];\n\t\tif (message) {\n\t\t\targs.push('-m', message);\n\t\t}\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'stash', 'store', ...args, id);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\t/** For a drop or store, which move `refs/stash` (or its reflog, the rest of the list) */\n\tprivate announceStashChanged(repoPath: string): void {\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t}\n}\n\nexport function convertStashesToStdin(stashOrStashes: GitStash | ReadonlyMap<string, GitStashCommit> | undefined): {\n\treadonly stdin: string | undefined;\n\treadonly stashes: Map<string, GitStashCommit>;\n\treadonly remappedIds: Map<string, string>;\n} {\n\tconst remappedIds = new Map<string, string>();\n\tif (stashOrStashes == null) return { stdin: undefined, stashes: new Map(), remappedIds: remappedIds };\n\n\tlet stdin: string | undefined;\n\tconst original = 'stashes' in stashOrStashes ? stashOrStashes.stashes : stashOrStashes;\n\tconst stashes = new Map<string, GitStashCommit>(original);\n\n\tif (original.size) {\n\t\tstdin = '';\n\t\tfor (const stash of original.values()) {\n\t\t\tstdin += `${stash.sha.substring(0, 9)}\\n`;\n\t\t\t// Include the stash's 2nd (index files) and 3rd (untracked files) parents (if they aren't already in the map)\n\t\t\tfor (const p of skip(stash.parents, 1)) {\n\t\t\t\tremappedIds.set(p, stash.sha);\n\n\t\t\t\tif (!stashes.has(p)) {\n\t\t\t\t\tstashes.set(p, stash);\n\t\t\t\t\tstdin += `${p.substring(0, 9)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { stdin: stdin || undefined, stashes: stashes, remappedIds: remappedIds };\n}\n\nconst stashSummaryRegex =\n\t// oxlint-disable-next-line no-control-regex\n\t/(?:(?:(?<wip>WIP) on|On) (?<onref>[^/](?!.*\\/\\.)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*@\\{)[^\\x00-\\x1F\\x7F ~^:?*[\\\\]+[^./]):\\s*)?(?<summary>.*)$/s;\n\nfunction createStash(\n\ts: ParsedStash | ParsedStashWithFiles,\n\trepoPath: string,\n\tcurrentUser: GitUser | undefined,\n): GitStashCommit {\n\t// `onRef` comes from the commit subject (%s), which git always prefixes with `On <branch>: …`\n\t// or `WIP on <branch>: …`. This holds even when the reflog message was customized\n\t// (autostash, `git stash store -m \"…\"`), so it's a reliable source\n\tlet onRef: string | undefined;\n\tconst subjectMatch = stashSummaryRegex.exec((s.commitSubject ?? '').trim());\n\tif (subjectMatch?.groups?.onref) {\n\t\tonRef = subjectMatch.groups.onref;\n\t}\n\n\t// The user-visible display message is derived from the reflog subject (%gs) so that short\n\t// custom messages like \"wip\", \"q\", or \"show args\" stay as the user wrote them instead of\n\t// being replaced by the verbose git-auto subject\n\tlet message = s.summary.trim();\n\tconst reflogMatch = stashSummaryRegex.exec(message);\n\tif (reflogMatch?.groups != null) {\n\t\tconst summary = reflogMatch.groups.summary.trim();\n\t\tif (summary.length === 0) {\n\t\t\tmessage = 'WIP';\n\t\t} else if (reflogMatch.groups.wip) {\n\t\t\tmessage = `WIP: ${summary}`;\n\t\t} else {\n\t\t\tmessage = summary;\n\t\t}\n\t}\n\n\tconst index = message.indexOf('\\n');\n\n\treturn new GitCommit(\n\t\trepoPath,\n\t\ts.sha,\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.authorDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.committedDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tindex !== -1 ? message.substring(0, index) : message,\n\t\ts.parents.split(' ') ?? [],\n\t\tmessage,\n\t\tcreateCommitFileset(s, repoPath, undefined),\n\t\ts.stats,\n\t\tundefined,\n\t\tundefined,\n\t\ts.stashName,\n\t\tonRef,\n\t) as GitStashCommit;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"stash.js","names":[],"sources":["../../../../git-cli/src/providers/stash.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { StashApplyError, StashPushError } from '@gitlens/git/errors.js';\nimport type { GitStashCommit } from '@gitlens/git/models/commit.js';\nimport { GitCommit, GitCommitIdentity } from '@gitlens/git/models/commit.js';\nimport { GitFileChange } from '@gitlens/git/models/fileChange.js';\nimport type { GitFileStatus } from '@gitlens/git/models/fileStatus.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitStash } from '@gitlens/git/models/stash.js';\nimport type { GitUser } from '@gitlens/git/models/user.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitStashSubProvider, StashApplyResult } from '@gitlens/git/providers/stash.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { skip } from '@gitlens/utils/iterable.js';\nimport { normalizePath, splitPath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, joinUriPath, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { gitFeaturesByVersion } from '../exec/features.js';\nimport type { Git } from '../exec/git.js';\nimport { getGitCommandError, GitError, GitErrors, isRunHookFailure, maxGitCliLength } from '../exec/git.js';\nimport type { IndexRefresher } from '../exec/indexRefresh.js';\nimport { refreshIndexAfter } from '../exec/indexRefresh.js';\nimport type { ParsedStash, ParsedStashWithFiles } from '../parsers/logParser.js';\nimport { getStashFilesOnlyLogParser, getStashLogParser } from '../parsers/logParser.js';\nimport { createCommitFileset } from './commitFilesetUtils.js';\n\n/** The one ref a stash write moves: a push, pop, drop or store changes `refs/stash` or its reflog, never another ref */\nconst stashRefs: readonly string[] = ['refs/stash'];\n\nexport class StashGitSubProvider implements GitStashSubProvider {\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t\tprivate readonly indexRefresher?: IndexRefresher,\n\t) {}\n\n\t@gate()\n\t@debug()\n\tasync applyStash(\n\t\trepoPath: string,\n\t\tstashNameOrSha: string,\n\t\toptions?: { deleteAfter?: boolean; index?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\tif (!stashNameOrSha) return { conflicted: false };\n\n\t\tconst args = ['stash', options?.deleteAfter ? 'pop' : 'apply'];\n\t\tif (options?.index) {\n\t\t\targs.push('--index');\n\t\t}\n\t\targs.push(stashNameOrSha);\n\t\treturn this.applyStashCore(repoPath, args, options?.deleteAfter ? 'stash-pop' : 'stash-apply', runOptions);\n\t}\n\n\tprivate async applyStashCore(\n\t\trepoPath: string,\n\t\targs: string[],\n\t\tconflictCommand: 'stash-apply' | 'stash-pop',\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\t// Only a clean pop is known to have moved `refs/stash`: a conflicted one keeps the entry\n\t\tlet dropped = false;\n\t\ttry {\n\t\t\tawait refreshIndexAfter(this.indexRefresher, repoPath, () =>\n\t\t\t\tthis.git.run({ cwd: repoPath, ...runOptions }, ...args),\n\t\t\t);\n\t\t\tdropped = conflictCommand === 'stash-pop';\n\t\t\treturn { conflicted: false };\n\t\t} catch (ex) {\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tconst msg: string = ex.message ?? '';\n\t\t\t\tif (\n\t\t\t\t\t(msg.includes('Auto-merging') && msg.includes('CONFLICT')) ||\n\t\t\t\t\t(ex instanceof GitError &&\n\t\t\t\t\t\t((ex.stdout?.includes('Auto-merging') && ex.stdout.includes('CONFLICT')) ||\n\t\t\t\t\t\t\tex.stdout?.includes('needs merge')))\n\t\t\t\t) {\n\t\t\t\t\tthis.context.hooks?.operations?.onConflicted?.(conflictCommand);\n\t\t\t\t\treturn { conflicted: true };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-apply',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashApplyError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A conflicted, failed or cancelled apply may already have changed the stash list or working tree\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\tif (dropped) {\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t\t\t} else {\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync createStash(repoPath: string, message?: string): Promise<string | undefined> {\n\t\tconst args = ['stash', 'create'];\n\t\tif (message) {\n\t\t\targs.push(message);\n\t\t}\n\n\t\tconst result = await this.git.run({ cwd: repoPath }, ...args);\n\t\treturn result.stdout.trim() || undefined;\n\t}\n\n\t@debug({ quiet: true })\n\tasync getStash(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tincludeFiles?: boolean;\n\t\t\treachableFrom?: string;\n\t\t\tsimilarityThreshold?: number | null;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStash | undefined> {\n\t\tif (repoPath == null) return undefined;\n\n\t\t// Resolve options against config up front so the cache key reflects the actual values used\n\t\t// to produce the cached payload — undefined inputs aren't conflated across config changes.\n\t\tconst cfg = this.context.config;\n\t\tconst includeFiles = options?.includeFiles ?? cfg?.commits.includeFileDetails?.(repoPath) ?? true;\n\t\tconst similarityThreshold = includeFiles\n\t\t\t? (options?.similarityThreshold ?? cfg?.commits.similarityThreshold ?? null)\n\t\t\t: null;\n\t\tconst reachableFrom = options?.reachableFrom;\n\n\t\t// Cache only the unfiltered stash list; reachability projection runs below by testing each\n\t\t// distinct stash parent against `reachableFrom` directly, so re-projecting is cheap\n\t\tconst cacheKey = `f${includeFiles ? 1 : 0}|s${similarityThreshold ?? ''}`;\n\n\t\tconst stash = await this.cache.getStash(\n\t\t\trepoPath,\n\t\t\tcacheKey,\n\t\t\tasync (commonPath, _cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst parser = getStashLogParser(includeFiles);\n\t\t\t\tconst args = [...parser.arguments];\n\n\t\t\t\tif (includeFiles) {\n\t\t\t\t\targs.push(`-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`);\n\t\t\t\t}\n\n\t\t\t\tconst result = await this.git.run({ cwd: repoPath, cancellation: signal }, 'stash', 'list', ...args);\n\n\t\t\t\tconst currentUser = await this.provider.config.getCurrentUser(repoPath);\n\n\t\t\t\tconst stashes = new Map<string, GitStashCommit>();\n\t\t\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\t\t\tstashes.set(s.sha, createStash(s, commonPath, currentUser));\n\t\t\t\t}\n\n\t\t\t\treturn { repoPath: commonPath, stashes: stashes };\n\t\t\t},\n\t\t\t{ cancellation: cancellation },\n\t\t);\n\n\t\tif (stash == null || !reachableFrom || !stash.stashes.size) return stash;\n\n\t\t// Copy because the cached `stash.stashes` map is shared and must not be mutated.\n\t\tconst stashes = new Map(stash.stashes);\n\n\t\tconst reachableStashes = new Set<string>();\n\n\t\t// Metadata pass: a stash belongs on `reachableFrom` iff git's auto-prepended\n\t\t// `On <branch>: …` (or `WIP on <branch>: …`) prefix in the stash commit subject names\n\t\t// this branch. `stashOnRef` is parsed from %s in createStash, so this covers autostashes\n\t\t// and custom-reflog stashes too.\n\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\tif (s.stashOnRef === reachableFrom) {\n\t\t\t\treachableStashes.add(sha);\n\t\t\t}\n\t\t}\n\n\t\t// Transitive pass for the rare detached-HEAD-on-stash chain (stash B created while HEAD\n\t\t// pointed at stash A). Such stashes have no `stashOnRef`, but if their parent is a stash\n\t\t// already marked reachable they should follow.\n\t\tlet changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\t\tif (!reachableStashes.has(sha) && s.parents.some(p => reachableStashes.has(p))) {\n\t\t\t\t\treachableStashes.add(sha);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (changed);\n\n\t\tfor (const [sha] of stash.stashes) {\n\t\t\tif (!reachableStashes.has(sha)) {\n\t\t\t\tstashes.delete(sha);\n\t\t\t}\n\t\t}\n\n\t\treturn { ...stash, stashes: stashes };\n\t}\n\n\t@debug({ quiet: true })\n\tasync getStashCommitFiles(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[]> {\n\t\tconst [stashFilesResult, stashUntrackedFilesResult] = await Promise.allSettled([\n\t\t\t// Don't include untracked files here, because we won't be able to tell them apart from added (and we need the untracked status)\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: false, ...options }, cancellation),\n\t\t\t// Check for any untracked files -- since git doesn't return them via `git stash list` :(\n\t\t\t// See https://stackoverflow.com/questions/12681529/\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: 'only', ...options }, cancellation),\n\t\t]);\n\n\t\tlet files = getSettledValue(stashFilesResult);\n\t\tconst untrackedFiles = getSettledValue(stashUntrackedFilesResult);\n\n\t\tif (files?.length && untrackedFiles?.length) {\n\t\t\tfiles.push(...untrackedFiles);\n\t\t} else {\n\t\t\tfiles = files ?? untrackedFiles;\n\t\t}\n\n\t\treturn files ?? [];\n\t}\n\n\tprivate async getStashCommitFilesCore(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null; untracked?: boolean | 'only' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[] | undefined> {\n\t\tconst args = [];\n\t\tif (options?.untracked) {\n\t\t\targs.push(options?.untracked === 'only' ? '--only-untracked' : '--include-untracked');\n\t\t}\n\n\t\tconst similarityThreshold = options?.similarityThreshold ?? this.context.config?.commits.similarityThreshold;\n\t\tif (similarityThreshold != null) {\n\t\t\targs.push(`-M${similarityThreshold}%`);\n\t\t}\n\n\t\tconst parser = getStashFilesOnlyLogParser();\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'stash',\n\t\t\t'show',\n\t\t\t...args,\n\t\t\t...parser.arguments,\n\t\t\tref,\n\t\t);\n\n\t\tconst repoUri = fileUri(normalizePath(repoPath));\n\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\treturn (\n\t\t\t\ts.files?.map(\n\t\t\t\t\tf =>\n\t\t\t\t\t\tnew GitFileChange(\n\t\t\t\t\t\t\trepoPath,\n\t\t\t\t\t\t\tf.path,\n\t\t\t\t\t\t\t(options?.untracked === 'only'\n\t\t\t\t\t\t\t\t? GitFileWorkingTreeStatus.Untracked\n\t\t\t\t\t\t\t\t: f.status) as GitFileStatus,\n\t\t\t\t\t\t\tjoinUriPath(repoUri, normalizePath(f.path)),\n\t\t\t\t\t\t\tf.originalPath,\n\t\t\t\t\t\t\tf.originalPath != null ? joinUriPath(repoUri, normalizePath(f.originalPath)) : undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.additions || f.deletions\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tadditions: f.additions ?? 0,\n\t\t\t\t\t\t\t\t\t\tdeletions: f.deletions ?? 0,\n\t\t\t\t\t\t\t\t\t\tchanges: 0,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.mode,\n\t\t\t\t\t\t),\n\t\t\t\t) ?? []\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t@debug()\n\tasync deleteStash(repoPath: string, stashName: string, sha?: string): Promise<void> {\n\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: true });\n\t}\n\n\t// Keyed without `options`, so a delete and a rename of the same stash share one drop: a second drop would take\n\t// the stash that moved up into its place\n\t@gate((rp, name, sha) => `${rp}\\0${name}\\0${sha ?? ''}`)\n\tprivate async deleteStashCore(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string | undefined,\n\t\toptions: { announce: boolean; verified?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (!stashName) return undefined;\n\n\t\tif (!options.verified) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.git.run({ cwd: repoPath }, 'stash', 'drop', stashName);\n\t\t} finally {\n\t\t\tif (options.announce) {\n\t\t\t\tthis.announceStashChanged(repoPath);\n\t\t\t}\n\t\t}\n\t\treturn result.stdout;\n\t}\n\n\tprivate async verifyStashSha(repoPath: string, stashName: string, sha: string | undefined): Promise<void> {\n\t\tif (!sha) return;\n\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, errors: 'ignore' },\n\t\t\t'show',\n\t\t\t'--format=%H',\n\t\t\t'--no-patch',\n\t\t\tstashName,\n\t\t);\n\t\tif (result.stdout.trim() !== sha) {\n\t\t\tthrow new Error(l10n.t('Unable to delete stash; mismatch with stash number'));\n\t\t}\n\t}\n\n\t@debug()\n\tasync renameStash(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string,\n\t\tmessage: string,\n\t\tstashOnRef?: string,\n\t): Promise<void> {\n\t\tif (stashName) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\t// The drop and the store announce once, after both ran, even if the store fails\n\t\ttry {\n\t\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: false, verified: true });\n\t\t\tawait this.git.run(\n\t\t\t\t{ cwd: repoPath },\n\t\t\t\t'stash',\n\t\t\t\t'store',\n\t\t\t\t'-m',\n\t\t\t\tstashOnRef ? `On ${stashOnRef}: ${message}` : message,\n\t\t\t\tsha,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug({ args: (repoPath, message, paths) => ({ repoPath: repoPath, message: message, paths: paths?.length }) })\n\tasync saveStash(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\tpathsOrUris?: (string | Uri)[],\n\t\toptions?: { includeUntracked?: boolean; keepIndex?: boolean; onlyStaged?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris?.map(toFsPath);\n\t\tif (!paths?.length) {\n\t\t\tawait this.stashPushCore(repoPath, message, options, runOptions);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.git.ensureSupports('git:stash:push:pathspecs', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Stashing individual files requires a newer version of Git (>= {0}) than is currently installed ({1}). Please retry by stashing everything or install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathspecs = paths.map(p => `./${splitPath(p, repoPath)[0]}`);\n\n\t\tlet stdin = await this.git.supports('git:stash:push:stdin');\n\t\tif (stdin && options?.onlyStaged && paths.length) {\n\t\t\t// Since Git doesn't support --staged with --pathspec-from-file try to pass them in directly\n\t\t\tstdin = false;\n\t\t}\n\n\t\t// If we don't support stdin, then error out if we are over the maximum allowed git cli length\n\t\tif (!stdin && countStringLength(pathspecs) > maxGitCliLength) {\n\t\t\tawait this.git.ensureSupports('git:stash:push:stdin', (requiredVersion, installedVersion) =>\n\t\t\t\tl10n.t(\n\t\t\t\t\t'Stashing so many files ({0}) at once requires a newer version of Git (>= {1}) than is currently installed ({2}). Please retry by stashing fewer files or install a more recent version of Git and try again.',\n\t\t\t\t\tpathspecs.length,\n\t\t\t\t\trequiredVersion,\n\t\t\t\t\tinstalledVersion,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait this.stashPushCore(\n\t\t\trepoPath,\n\t\t\tmessage,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tpathspecs: pathspecs,\n\t\t\t\tstdin: stdin,\n\t\t\t},\n\t\t\trunOptions,\n\t\t);\n\t}\n\n\tprivate async stashPushCore(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\toptions?: {\n\t\t\tincludeUntracked?: boolean;\n\t\t\tkeepIndex?: boolean;\n\t\t\tonlyStaged?: boolean;\n\t\t\tpathspecs?: string[];\n\t\t\tstdin?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst params = ['stash', 'push'];\n\n\t\tif ((options?.includeUntracked || options?.pathspecs?.length) && !options?.onlyStaged) {\n\t\t\tparams.push('--include-untracked');\n\t\t}\n\n\t\t// `git stash push --keep-index --include-untracked -- <pathspec>` hits a bug in git when the\n\t\t// pathspec names an untracked file: the restoring checkout can't match an untracked path in the\n\t\t// index tree, so it fails and the staged changes are lost.\n\t\t//\n\t\t// $ mkdir stash-test && cd stash-test && git init\n\t\t// $ echo a > a.txt\n\t\t// $ git add a.txt\n\t\t// $ git commit -m init\n\t\t// $ echo b > b.txt\n\t\t// $ git stash push --keep-index --include-untracked -- b.txt\n\t\t// Saved working directory and index state WIP on main: 8a280fe init\n\t\t// error: pathspec ':(prefix:0)b.txt' did not match any file(s) known to git\n\t\t//\n\t\t// Only suppress --keep-index for that case — when the selection actually includes untracked\n\t\t// files (`includeUntracked`) AND we're stashing by pathspec. Keying off `includeUntracked` (the\n\t\t// caller's intent) rather than the `--include-untracked` flag is deliberate: we add\n\t\t// `--include-untracked` to every pathspec push above as a safety net, but a tracked-only\n\t\t// selection can — and must — still keep the index intact.\n\t\tif (options?.keepIndex && !(options?.includeUntracked && options?.pathspecs?.length)) {\n\t\t\tparams.push('--keep-index');\n\t\t}\n\n\t\tif (options?.onlyStaged) {\n\t\t\tif (await this.git.supports('git:stash:push:staged')) {\n\t\t\t\tparams.push('--staged');\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tl10n.t(\n\t\t\t\t\t\t'Git version {0} or higher is required for --staged',\n\t\t\t\t\t\tString(gitFeaturesByVersion.get('git:stash:push:staged')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (message) {\n\t\t\tparams.push('-m', message);\n\t\t}\n\n\t\tlet stdin: string | undefined;\n\t\tif (options?.pathspecs?.length) {\n\t\t\tif (options.stdin) {\n\t\t\t\tstdin = options.pathspecs.join('\\0');\n\t\t\t\tparams.push('--pathspec-from-file=-', '--pathspec-file-nul', '--');\n\t\t\t} else {\n\t\t\t\tparams.push('--', ...options.pathspecs);\n\t\t\t}\n\t\t} else {\n\t\t\tparams.push('--');\n\t\t}\n\n\t\tlet nothingToSave = false;\n\t\ttry {\n\t\t\tconst result = await refreshIndexAfter(this.indexRefresher, repoPath, () =>\n\t\t\t\tthis.git.run({ cwd: repoPath, ...runOptions, stdin: stdin }, ...params),\n\t\t\t);\n\t\t\tif (GitErrors.stashNothingToSave.test(result.stdout)) {\n\t\t\t\tnothingToSave = true;\n\t\t\t\tthrow new StashPushError({\n\t\t\t\t\treason: 'nothingToSave',\n\t\t\t\t\tgitCommand: { repoPath: repoPath, args: params },\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof StashPushError || isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-push',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashPushError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: params } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled push may already have stashed, and reset the working tree; one with nothing to\n\t\t\t// save changed nothing\n\t\t\tif (!nothingToSave) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync saveSnapshot(repoPath: string, message?: string): Promise<void> {\n\t\tconst result = await this.git.run({ cwd: repoPath }, 'stash', 'create');\n\t\tconst id = result.stdout.trim() || undefined;\n\t\tif (id == null) return;\n\n\t\tconst args = [];\n\t\tif (message) {\n\t\t\targs.push('-m', message);\n\t\t}\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'stash', 'store', ...args, id);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\t/** For a drop or store, which move `refs/stash` (or its reflog, the rest of the list) */\n\tprivate announceStashChanged(repoPath: string): void {\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash'], stashRefs);\n\t}\n}\n\nexport function convertStashesToStdin(stashOrStashes: GitStash | ReadonlyMap<string, GitStashCommit> | undefined): {\n\treadonly stdin: string | undefined;\n\treadonly stashes: Map<string, GitStashCommit>;\n\treadonly remappedIds: Map<string, string>;\n} {\n\tconst remappedIds = new Map<string, string>();\n\tif (stashOrStashes == null) return { stdin: undefined, stashes: new Map(), remappedIds: remappedIds };\n\n\tlet stdin: string | undefined;\n\tconst original = 'stashes' in stashOrStashes ? stashOrStashes.stashes : stashOrStashes;\n\tconst stashes = new Map<string, GitStashCommit>(original);\n\n\tif (original.size) {\n\t\tstdin = '';\n\t\tfor (const stash of original.values()) {\n\t\t\tstdin += `${stash.sha.substring(0, 9)}\\n`;\n\t\t\t// Include the stash's 2nd (index files) and 3rd (untracked files) parents (if they aren't already in the map)\n\t\t\tfor (const p of skip(stash.parents, 1)) {\n\t\t\t\tremappedIds.set(p, stash.sha);\n\n\t\t\t\tif (!stashes.has(p)) {\n\t\t\t\t\tstashes.set(p, stash);\n\t\t\t\t\tstdin += `${p.substring(0, 9)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { stdin: stdin || undefined, stashes: stashes, remappedIds: remappedIds };\n}\n\nconst stashSummaryRegex =\n\t// oxlint-disable-next-line no-control-regex\n\t/(?:(?:(?<wip>WIP) on|On) (?<onref>[^/](?!.*\\/\\.)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*@\\{)[^\\x00-\\x1F\\x7F ~^:?*[\\\\]+[^./]):\\s*)?(?<summary>.*)$/s;\n\nfunction createStash(\n\ts: ParsedStash | ParsedStashWithFiles,\n\trepoPath: string,\n\tcurrentUser: GitUser | undefined,\n): GitStashCommit {\n\t// `onRef` comes from the commit subject (%s), which git always prefixes with `On <branch>: …`\n\t// or `WIP on <branch>: …`. This holds even when the reflog message was customized\n\t// (autostash, `git stash store -m \"…\"`), so it's a reliable source\n\tlet onRef: string | undefined;\n\tconst subjectMatch = stashSummaryRegex.exec((s.commitSubject ?? '').trim());\n\tif (subjectMatch?.groups?.onref) {\n\t\tonRef = subjectMatch.groups.onref;\n\t}\n\n\t// The user-visible display message is derived from the reflog subject (%gs) so that short\n\t// custom messages like \"wip\", \"q\", or \"show args\" stay as the user wrote them instead of\n\t// being replaced by the verbose git-auto subject\n\tlet message = s.summary.trim();\n\tconst reflogMatch = stashSummaryRegex.exec(message);\n\tif (reflogMatch?.groups != null) {\n\t\tconst summary = reflogMatch.groups.summary.trim();\n\t\tif (summary.length === 0) {\n\t\t\tmessage = 'WIP';\n\t\t} else if (reflogMatch.groups.wip) {\n\t\t\tmessage = `WIP: ${summary}`;\n\t\t} else {\n\t\t\tmessage = summary;\n\t\t}\n\t}\n\n\tconst index = message.indexOf('\\n');\n\n\treturn new GitCommit(\n\t\trepoPath,\n\t\ts.sha,\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.authorDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.committedDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tindex !== -1 ? message.substring(0, index) : message,\n\t\ts.parents.split(' ') ?? [],\n\t\tmessage,\n\t\tcreateCommitFileset(s, repoPath, undefined),\n\t\ts.stats,\n\t\tundefined,\n\t\tundefined,\n\t\ts.stashName,\n\t\tonRef,\n\t) as GitStashCommit;\n}\n"],"mappings":"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"}
@@ -5,6 +5,7 @@ import { Cache } from "../../git/cache.js";
5
5
  import { GitOperationRunOptions } from "../../git/providers/operations.js";
6
6
  import { GitWorktreesSubProvider } from "../../git/providers/worktrees.js";
7
7
  import { Git } from "../exec/git.js";
8
+ import { IndexRefresher } from "../exec/indexRefresh.js";
8
9
  import { CliGitProviderInternal } from "../cliGitProvider.js";
9
10
  //#region ../git-cli/src/providers/worktrees.d.ts
10
11
  export declare class WorktreesGitSubProvider implements GitWorktreesSubProvider {
@@ -17,6 +18,8 @@ export declare class WorktreesGitSubProvider implements GitWorktreesSubProvider
17
18
  * when they can't be read; given only when folders are registered
18
19
  */
19
20
  private readonly readIgnoredWorktreeRoots?;
21
+ /** Refreshes the index of a worktree it just checked out */
22
+ private readonly indexRefresher?;
20
23
  /** Per common path, the read whose `git worktree list` hasn't started yet */
21
24
  private readonly _unspawnedReads;
22
25
  /**
@@ -29,7 +32,9 @@ export declare class WorktreesGitSubProvider implements GitWorktreesSubProvider
29
32
  * Reads the absolute folders whose worktrees a repository's list leaves out, rejecting (or answering `undefined`)
30
33
  * when they can't be read; given only when folders are registered
31
34
  */
32
- readIgnoredWorktreeRoots?: ((repoPath: string) => Promise<readonly string[] | undefined>) | undefined);
35
+ readIgnoredWorktreeRoots?: ((repoPath: string) => Promise<readonly string[] | undefined>) | undefined,
36
+ /** Refreshes the index of a worktree it just checked out */
37
+ indexRefresher?: IndexRefresher | undefined);
33
38
  /**
34
39
  * Creates a worktree (`git worktree add`). `runOptions` are spread into the underlying `git.run` call, so a
35
40
  * large checkout can run without the default command timeout (`{ timeout: 0 }`) and still be cancelled.
@@ -9,6 +9,7 @@ import { WorktreeCreateError, WorktreeDeleteError } from "../../git/errors.js";
9
9
  import { mayWriteTracking } from "../exec/commandClassifier.js";
10
10
  import { isWindows } from "../../utils/env/node/platform.js";
11
11
  import { GitErrors, getGitCommandError, isRunHookFailure } from "../exec/git.js";
12
+ import { refreshIndexAfter } from "../exec/indexRefresh.js";
12
13
  import { GitWorktree } from "../../git/models/worktree.js";
13
14
  import { parseGitWorktrees } from "../parsers/worktreeParser.js";
14
15
  import { join, resolve } from "path";
@@ -70,6 +71,7 @@ var WorktreesGitSubProvider = class {
70
71
  cache;
71
72
  provider;
72
73
  readIgnoredWorktreeRoots;
74
+ indexRefresher;
73
75
  /** Per common path, the read whose `git worktree list` hasn't started yet */
74
76
  _unspawnedReads = /* @__PURE__ */ new Map();
75
77
  /**
@@ -77,12 +79,13 @@ var WorktreesGitSubProvider = class {
77
79
  * listings never agree, which re-reading the branches again can't fix until the list changes
78
80
  */
79
81
  _lastingDisagreements = /* @__PURE__ */ new Map();
80
- constructor(context, git, cache, provider, readIgnoredWorktreeRoots) {
82
+ constructor(context, git, cache, provider, readIgnoredWorktreeRoots, indexRefresher) {
81
83
  this.context = context;
82
84
  this.git = git;
83
85
  this.cache = cache;
84
86
  this.provider = provider;
85
87
  this.readIgnoredWorktreeRoots = readIgnoredWorktreeRoots;
88
+ this.indexRefresher = indexRefresher;
86
89
  }
87
90
  /**
88
91
  * Creates a worktree (`git worktree add`). `runOptions` are spread into the underlying `git.run` call, so a
@@ -100,10 +103,11 @@ var WorktreesGitSubProvider = class {
100
103
  let createdBranch = options?.createBranch;
101
104
  let mayHaveCreatedBranch = false;
102
105
  try {
103
- const result = await this.git.run({
106
+ const run = () => this.git.run({
104
107
  cwd: repoPath,
105
108
  ...runOptions
106
109
  }, ...args);
110
+ const result = await refreshIndexAfter(this.indexRefresher, normalizePath(resolve(repoPath, path)), run);
107
111
  createdBranch ??= getNewWorktreeBranch(result.stderr);
108
112
  } catch (ex) {
109
113
  scope?.error(ex);
@@ -1 +1 @@
1
- {"version":3,"file":"worktrees.js","names":["basename","fs"],"sources":["../../../../git-cli/src/providers/worktrees.ts"],"sourcesContent":["import { exec } from 'child_process';\nimport { promises as fs } from 'fs';\nimport { join, resolve } from 'path';\nimport * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { WorktreeCreateError, WorktreeDeleteError } from '@gitlens/git/errors.js';\nimport type { GitBranch } from '@gitlens/git/models/branch.js';\nimport type { WorkspaceFolderResolver } from '@gitlens/git/models/worktree.js';\nimport { GitWorktree } from '@gitlens/git/models/worktree.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitWorktreesSubProvider } from '@gitlens/git/providers/worktrees.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { isWindows } from '@gitlens/utils/env/node/platform.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { basename, isDescendant, normalizePath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { CacheController } from '@gitlens/utils/promiseCache.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { mayWriteTracking } from '../exec/commandClassifier.js';\nimport type { Git, GitError } from '../exec/git.js';\nimport { getGitCommandError, GitErrors, isRunHookFailure } from '../exec/git.js';\nimport { parseGitWorktrees } from '../parsers/worktreeParser.js';\n\n/** Extracts the lock reason from Git's `cannot remove a locked working tree` output, when it provides one */\nfunction getLockReason(ex: GitError): string | undefined {\n\treturn GitErrors.worktreeLockedReason.exec(ex.stderr || ex.stdout || ex.message || '')?.[1].trim() || undefined;\n}\n\n/**\n * The branch `git worktree add` says it created, from the `Preparing worktree (new branch '<name>')` line it writes to\n * stderr (git 2.17+, in English since every run sets `LC_ALL=C`)\n */\nfunction getNewWorktreeBranch(stderr: string | undefined): string | undefined {\n\treturn stderr ? /^Preparing worktree \\(new branch '(.+)'\\)$/m.exec(stderr)?.[1] : undefined;\n}\n\nconst unbornSha = /^0+$/;\n\n/**\n * Where `git worktree list` contradicts the branch list it was paired with, or `undefined` when they agree. `switched`\n * holds the worktrees whose checked-out branch differs from the one the branch list places there.\n */\nfunction findStaleBranches(\n\tworktrees: readonly GitWorktree[],\n\tbranches: readonly GitBranch[],\n\t/** Whether git says where each branch is checked out (`%(worktreepath)`); before it, only the current branch's is known */\n\tknowsPaths: boolean,\n): { switched: string[] } | undefined {\n\tif (!worktrees.length) return undefined;\n\n\tconst byName = new Map<string, GitBranch>();\n\tconst byPath = new Map<string, GitBranch>();\n\tfor (const b of branches) {\n\t\t// A detached HEAD's stand-in branch names no ref\n\t\tif (b.remote || b.detached) continue;\n\n\t\tbyName.set(b.name, b);\n\t\t// A rebasing branch's worktree lists as detached\n\t\tif (b.worktree && !b.rebasing) {\n\t\t\tbyPath.set(normalizePath(b.worktree.path), b);\n\t\t}\n\t}\n\n\t// Git places a branch checked out in several worktrees (`worktree add --force`) at only one of them\n\tconst listedBranches = new Map(worktrees.map(w => [w.path, w.branchName]));\n\n\tlet stale = false;\n\tconst switched: string[] = [];\n\tfor (const w of worktrees) {\n\t\t// A bare repository checks nothing out, though git places the branch its HEAD names there\n\t\tif (w.type === 'bare') {\n\t\t\tbyPath.delete(w.path);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst listed = byPath.get(w.path);\n\t\tif (listed != null) {\n\t\t\tbyPath.delete(w.path);\n\t\t\tif (listed.name !== w.branchName) {\n\t\t\t\tswitched.push(w.path);\n\t\t\t\tstale = true;\n\t\t\t}\n\t\t} else if (knowsPaths && w.branchName != null) {\n\t\t\t// Detached, or not yet a worktree, when the branches were read\n\t\t\tswitched.push(w.path);\n\t\t}\n\n\t\t// An unborn branch has no ref for the branch list to know\n\t\tif (w.branchName == null || !w.sha || unbornSha.test(w.sha)) continue;\n\n\t\tconst branch = byName.get(w.branchName);\n\t\tif (\n\t\t\tbranch == null ||\n\t\t\t(branch.sha != null && branch.sha !== w.sha) ||\n\t\t\tbranch.worktree === false ||\n\t\t\t(branch.worktree != null && listedBranches.get(normalizePath(branch.worktree.path)) !== w.branchName)\n\t\t) {\n\t\t\tstale = true;\n\t\t}\n\t}\n\n\t// A branch placed in a worktree that no longer lists it was removed or switched away\n\tif (byPath.size) {\n\t\tstale = true;\n\t}\n\n\treturn stale ? { switched: switched } : undefined;\n}\n\nexport class WorktreesGitSubProvider implements GitWorktreesSubProvider {\n\t/** Per common path, the read whose `git worktree list` hasn't started yet */\n\tprivate readonly _unspawnedReads = new Map<string, object>();\n\t/**\n\t * Per common path, the `git worktree list` output a fresh branch list still contradicted: a layout where git's two\n\t * listings never agree, which re-reading the branches again can't fix until the list changes\n\t */\n\tprivate readonly _lastingDisagreements = new Map<string, string>();\n\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t\t/**\n\t\t * Reads the absolute folders whose worktrees a repository's list leaves out, rejecting (or answering `undefined`)\n\t\t * when they can't be read; given only when folders are registered\n\t\t */\n\t\tprivate readonly readIgnoredWorktreeRoots?: (repoPath: string) => Promise<readonly string[] | undefined>,\n\t) {}\n\n\t/**\n\t * Creates a worktree (`git worktree add`). `runOptions` are spread into the underlying `git.run` call, so a\n\t * large checkout can run without the default command timeout (`{ timeout: 0 }`) and still be cancelled.\n\t */\n\t@debug()\n\tasync createWorktree(\n\t\trepoPath: string,\n\t\tpath: string,\n\t\toptions?: {\n\t\t\tcommitish?: string;\n\t\t\tcreateBranch?: string;\n\t\t\tdetach?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tnoTracking?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst args = ['worktree', 'add'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t}\n\t\tif (options?.createBranch) {\n\t\t\targs.push('-b', options.createBranch);\n\t\t}\n\t\tif (options?.createBranch && options.noTracking) {\n\t\t\targs.push('--no-track');\n\t\t}\n\t\tif (options?.detach) {\n\t\t\targs.push('--detach');\n\t\t}\n\t\targs.push(path);\n\t\tif (options?.commitish) {\n\t\t\targs.push(options.commitish);\n\t\t}\n\n\t\t// Without `-b`, git may still create a branch: from a remote branch of the commitish's name, or named after the\n\t\t// path when no commitish is given\n\t\tlet createdBranch = options?.createBranch;\n\t\t// A cancelled or timed-out run, or a host-rejected retry, leaves no output to name the branch git may have created\n\t\tlet mayHaveCreatedBranch = false;\n\t\ttry {\n\t\t\tconst result = await this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\t\t\tcreatedBranch ??= getNewWorktreeBranch(result.stderr);\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// `?.`: a host's index-lock retry hook may reject with anything, `undefined` included\n\t\t\tcreatedBranch ??= getNewWorktreeBranch((ex as GitError | undefined)?.stderr);\n\n\t\t\t// A cancelled or timed-out checkout, or a host-rejected index-lock retry, is not git refusing the worktree\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) {\n\t\t\t\tmayHaveCreatedBranch = createdBranch == null && !options?.detach;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'worktree-create',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew WorktreeCreateError(\n\t\t\t\t\t\t{ reason: reason, gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex as GitError,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled add may already have created the branch (and its tracking in `.git/config`) or\n\t\t\t// the worktree directory.\n\t\t\t//\n\t\t\t// The tracking isn't announced as a `config` change, only evicted: git may also write repository-wide\n\t\t\t// keys (`extensions.relativeWorktrees` under `worktree.useRelativePaths`), so the write can't claim its\n\t\t\t// config change is confined to the new branch, and an unconfined one would refresh every worktree on each\n\t\t\t// add. The watcher's report of the file says what changed in it instead.\n\t\t\tif (createdBranch) {\n\t\t\t\t// Evict the cached base only — see `checkout -b` for why the persisted keys are left alone.\n\t\t\t\tthis.cache.deleteBaseBranchName(repoPath, createdBranch);\n\t\t\t\t// A branch git created on its own may track a remote branch, whatever the commitish looks like\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(\n\t\t\t\t\trepoPath,\n\t\t\t\t\t...(!options?.createBranch || mayWriteTracking(options.commitish, options.noTracking)\n\t\t\t\t\t\t? (['branches', 'config', 'worktrees'] as const)\n\t\t\t\t\t\t: (['branches', 'worktrees'] as const)),\n\t\t\t\t);\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(\n\t\t\t\t\trepoPath,\n\t\t\t\t\t['worktrees', 'worktreeHead', 'heads'],\n\t\t\t\t\t[`refs/heads/${createdBranch}`],\n\t\t\t\t);\n\t\t\t} else if (mayHaveCreatedBranch) {\n\t\t\t\t// Git creates the branch before checking it out, so a run cut short may have left one it never named\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'config', 'worktrees');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead', 'heads']);\n\t\t\t} else {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync createWorktreeWithResult(\n\t\trepoPath: string,\n\t\tpath: string,\n\t\toptions?: {\n\t\t\tcommitish?: string;\n\t\t\tcreateBranch?: string;\n\t\t\tdetach?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tnoTracking?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<GitWorktree | undefined> {\n\t\tawait this.createWorktree(repoPath, path, options, runOptions);\n\t\tconst normalized = normalizePath(path);\n\t\treturn this.getWorktree(\n\t\t\trepoPath,\n\t\t\tw => normalizePath(w.path) === normalized,\n\t\t\tundefined,\n\t\t\trunOptions?.cancellation,\n\t\t);\n\t}\n\n\t@debug({ quiet: true })\n\tasync getWorktree(\n\t\trepoPath: string,\n\t\tpredicate: (w: GitWorktree) => boolean,\n\t\toptions?: { force?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree | undefined> {\n\t\treturn (await this.getWorktrees(repoPath, options, cancellation)).find(predicate);\n\t}\n\n\t@debug({ quiet: true })\n\tasync getWorktrees(\n\t\trepoPath: string,\n\t\toptions?: { force?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree[]> {\n\t\t// A pending read that hasn't started `git worktree list` will see the state as of this call, so it is joined,\n\t\t// whether it was pending as the call started or is once the call would evict (another forced read's, say)\n\t\tlet force = options?.force === true && !this._unspawnedReads.has(this.cache.getCommonPath(repoPath));\n\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Displaying worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tif (force && this._unspawnedReads.has(this.cache.getCommonPath(repoPath))) {\n\t\t\tforce = false;\n\t\t}\n\n\t\treturn this.cache.getWorktrees(\n\t\t\trepoPath,\n\t\t\tasync (commonPath, cacheable, signal) => {\n\t\t\t\tconst unspawned = {};\n\t\t\t\tthis._unspawnedReads.set(commonPath, unspawned);\n\t\t\t\tconst onSpawned = () => {\n\t\t\t\t\tif (this._unspawnedReads.get(commonPath) === unspawned) {\n\t\t\t\t\t\tthis._unspawnedReads.delete(commonPath);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.readWorktrees(repoPath, commonPath, cacheable, signal ?? cancellation, onSpawned);\n\t\t\t\t} finally {\n\t\t\t\t\tonSpawned();\n\t\t\t\t}\n\t\t\t},\n\t\t\tforce ? { force: true } : undefined,\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async readWorktrees(\n\t\trepoPath: string,\n\t\tcommonPath: string,\n\t\tcacheable: CacheController,\n\t\tsignal: AbortSignal | undefined,\n\t\tonSpawn: () => void,\n\t): Promise<GitWorktree[]> {\n\t\t// Read beside the list, which it doesn't depend on. `commonPath` is the main worktree, not the git dir,\n\t\t// so the roots come from the repository's own git dir\n\t\tconst rootsRead = this.readIgnoredWorktreeRoots?.(repoPath).catch(() => undefined);\n\t\tconst [dataResult, branchesResult] = await Promise.allSettled([\n\t\t\tthis.git.run(\n\t\t\t\t{ cwd: commonPath, cancellation: signal, onSpawn: onSpawn },\n\t\t\t\t'worktree',\n\t\t\t\t'list',\n\t\t\t\t'--porcelain',\n\t\t\t),\n\t\t\tthis.provider.branches.getBranches(commonPath, undefined, signal),\n\t\t]);\n\n\t\tif (dataResult.status === 'rejected') {\n\t\t\t// Don't cache a bogus empty result for a transient command failure — retry on next access.\n\t\t\tcacheable.invalidate();\n\t\t}\n\n\t\tconst getWorkspaceFolder: WorkspaceFolderResolver | undefined = this.context.workspace\n\t\t\t? uri => {\n\t\t\t\t\tconst folder = this.context.workspace!.getFolder(uri.fsPath);\n\t\t\t\t\tif (folder == null) return undefined;\n\t\t\t\t\treturn { uri: fileUri(folder.path), name: basename(folder.path) };\n\t\t\t\t}\n\t\t\t: undefined;\n\n\t\tconst data = getSettledValue(dataResult)?.stdout;\n\t\tlet worktrees = parseGitWorktrees(\n\t\t\tdata,\n\t\t\tcommonPath,\n\t\t\tgetSettledValue(branchesResult)?.values ?? [],\n\t\t\tgetWorkspaceFolder,\n\t\t);\n\n\t\t// The branches come from the cache, which can lag the list just read (a forced read pairs a fresh list with\n\t\t// them). Where the list contradicts them it proves them stale, so they are re-read, once\n\t\tconst knowsPaths = await this.git.supports('git:for-each-ref:worktreePath');\n\t\tconst stale =\n\t\t\tbranchesResult.status === 'fulfilled'\n\t\t\t\t? findStaleBranches(worktrees, branchesResult.value.values, knowsPaths)\n\t\t\t\t: undefined;\n\t\tif (stale == null) {\n\t\t\tthis._lastingDisagreements.delete(commonPath);\n\t\t} else if (this._lastingDisagreements.get(commonPath) !== data) {\n\t\t\tthis.context.hooks?.cache?.onReset?.(commonPath, 'branches');\n\t\t\tfor (const path of stale.switched) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(path, 'branch');\n\t\t\t}\n\n\t\t\tlet branches: GitBranch[] | undefined;\n\t\t\ttry {\n\t\t\t\t({ values: branches } = await this.provider.branches.getBranches(commonPath, undefined, signal));\n\t\t\t} catch {\n\t\t\t\t// Keep the branches matched from the stale list, but not in the cache\n\t\t\t\tcacheable.invalidate();\n\t\t\t}\n\n\t\t\tif (branches != null) {\n\t\t\t\tworktrees = parseGitWorktrees(data, commonPath, branches, getWorkspaceFolder);\n\t\t\t\tif (data != null && findStaleBranches(worktrees, branches, knowsPaths) != null) {\n\t\t\t\t\tthis._lastingDisagreements.set(commonPath, data);\n\t\t\t\t}\n\t\t\t\t// The host's views show the branches the watcher missed a change of; which moved is unknown. Only the\n\t\t\t\t// host hears it: announced as a write of core's, the watch layer would take an outside `heads` report\n\t\t\t\t// arriving meanwhile for its echo and drop it, though nothing of the kind was evicted for it\n\t\t\t\tfor (const path of new Set([commonPath, ...this.cache.getWorktreePaths(commonPath)])) {\n\t\t\t\t\tthis.provider.notifyHost(path, ['heads']);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (rootsRead != null) {\n\t\t\tconst roots = await rootsRead;\n\t\t\tif (roots == null) {\n\t\t\t\t// The folders couldn't be read: an unfiltered list would keep ignored worktrees in the shared\n\t\t\t\t// cache until the next change\n\t\t\t\tcacheable.invalidate();\n\t\t\t} else if (roots.length) {\n\t\t\t\tworktrees = worktrees.filter(w => !roots.some(root => isDescendant(normalizePath(w.path), root)));\n\t\t\t}\n\t\t}\n\n\t\t// Older git prints a bare `locked` even when a reason exists; recover it from the admin dir\n\t\tif (await this.git.supports('git:worktree:list:lock-reason')) return worktrees;\n\n\t\treturn Promise.all(worktrees.map(w => this.withLockReason(w)));\n\t}\n\n\tprivate async withLockReason(worktree: GitWorktree): Promise<GitWorktree> {\n\t\tif (worktree.locked !== true || worktree.isDefault || worktree.type === 'bare') return worktree;\n\n\t\ttry {\n\t\t\t// A linked worktree's `.git` is a file: `gitdir: <admin dir>`, relative to the worktree when not absolute\n\t\t\tconst dotGit = join(worktree.uri.fsPath, '.git');\n\t\t\tconst match = /^gitdir:\\s*(.+?)\\s*$/m.exec(await fs.readFile(dotGit, 'utf8'));\n\t\t\tif (match == null) return worktree;\n\n\t\t\tconst reason = (await fs.readFile(join(resolve(worktree.uri.fsPath, match[1]), 'locked'), 'utf8')).trim();\n\t\t\tif (!reason) return worktree;\n\n\t\t\treturn new GitWorktree(\n\t\t\t\tworktree.isDefault,\n\t\t\t\tworktree.type,\n\t\t\t\tworktree.repoPath,\n\t\t\t\tworktree.uri,\n\t\t\t\treason,\n\t\t\t\tworktree.prunable,\n\t\t\t\tworktree.sha,\n\t\t\t\tworktree.branch,\n\t\t\t\tworktree.workspaceFolder,\n\t\t\t\tworktree.branchName,\n\t\t\t);\n\t\t} catch {\n\t\t\treturn worktree;\n\t\t}\n\t}\n\n\t@debug({ quiet: true })\n\tgetWorktreesDefaultUri(repoPath: string): Uri | undefined {\n\t\treturn this.context.workspace?.getWorktreeDefaultUri?.(repoPath);\n\t}\n\n\t/**\n\t * Deletes a worktree (`git worktree remove`). Pass `force: 'locked'` to also override a locked worktree.\n\t *\n\t * `runOptions` are spread into the underlying `git.run` call (e.g. `{ timeout: 0 }` for a large worktree\n\t * whose removal may exceed the default command timeout).\n\t *\n\t * On failure, the thrown {@link WorktreeDeleteError}'s `original` property carries the raw\n\t * {@link GitError} (stderr/stdout/exit code) untouched — a caller that needs to classify a\n\t * platform-specific failure (e.g. a Windows file-lock retry) can read it directly rather than parsing\n\t * the typed error's message.\n\t */\n\t@debug()\n\tasync deleteWorktree(\n\t\trepoPath: string,\n\t\tpath: string | Uri,\n\t\toptions?: { force?: boolean | 'locked' },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst scope = getScopedLogger();\n\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Deleting worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst args = ['worktree', 'remove'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t\t// Git requires a second `--force` to remove a locked worktree\n\t\t\tif (options.force === 'locked') {\n\t\t\t\targs.push('--force');\n\t\t\t}\n\t\t}\n\n\t\tconst pathStr = normalizePath(toFsPath(path));\n\t\targs.push(pathStr);\n\n\t\tlet deleted = false;\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args);\n\t\t\tdeleted = true;\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// A cancelled or timed-out removal (`runOptions.cancellation`/`timeout`), or a host-rejected index-lock\n\t\t\t// retry, is not git refusing it, and wrapping it would hand the caller a `WorktreeDeleteError` whose\n\t\t\t// `original` is no `GitError` at all\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tconst gitError = getGitCommandError(\n\t\t\t\t'worktree-delete',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew WorktreeDeleteError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treason: reason,\n\t\t\t\t\t\t\tlockReason: reason === 'locked' ? getLockReason(ex as GitError) : undefined,\n\t\t\t\t\t\t\tgitCommand: { repoPath: repoPath, args: args },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tex as GitError,\n\t\t\t\t\t),\n\t\t\t);\n\n\t\t\tif (gitError.details.reason === 'directoryNotEmpty') {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`Failed to fully delete worktree '${pathStr}' because it is not empty. Attempting to delete it manually.`,\n\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tawait fs.rm(pathStr, { force: true, recursive: true });\n\t\t\t\t\tdeleted = true;\n\t\t\t\t\treturn;\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tif (isWindows) {\n\t\t\t\t\t\tconst match = /EPERM: operation not permitted, unlink '(.*?)'/i.exec((ex as GitError).message);\n\t\t\t\t\t\tif (match != null) {\n\t\t\t\t\t\t\tscope?.warn(\n\t\t\t\t\t\t\t\t`Failed to manually delete '${pathStr}' because it is in use. Attempting to forcefully delete it.`,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Windows-specific: `del` via cmd.exe to force-remove a locked symlink.\n\t\t\t\t\t\t\t// Node's fs.rm/unlink fails with EPERM when the symlink target is in use.\n\t\t\t\t\t\t\tfunction deleteInUseSymlink(symlink: string) {\n\t\t\t\t\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\t\t\t\t\texec(`del \"${symlink}\"`, (ex, stdout, stderr) => {\n\t\t\t\t\t\t\t\t\t\tif (ex) {\n\t\t\t\t\t\t\t\t\t\t\treject(ex instanceof Error ? ex : new Error(String(ex)));\n\t\t\t\t\t\t\t\t\t\t} else if (stderr) {\n\t\t\t\t\t\t\t\t\t\t\treject(new Error(stderr));\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tresolve(stdout);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst [, file] = match;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait deleteInUseSymlink(file);\n\t\t\t\t\t\t\t\tawait fs.rm(pathStr, { force: true, recursive: true, maxRetries: 1, retryDelay: 1 });\n\t\t\t\t\t\t\t\tdeleted = true;\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t\tscope?.error(ex, `Failed to forcefully delete '${pathStr}' because it is in use.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow gitError;\n\t\t} finally {\n\t\t\tif (deleted) {\n\t\t\t\t// Clean up Cache registry + per-worktree cache entries for the deleted worktree.\n\t\t\t\t// Order matters: unregister before emitting the repo-level change so any listener\n\t\t\t\t// that re-queries worktree-aware state sees the registry already updated.\n\t\t\t\tthis.cache.unregisterRepoPath(pathStr);\n\t\t\t}\n\t\t\t// A failed or cancelled removal may already have taken the worktree's files or admin entry\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync pruneWorktrees(repoPath: string, options?: { expire?: string }): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Pruning worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst before = await this.listWorktreePaths(repoPath);\n\n\t\tconst args = ['worktree', 'prune'];\n\t\tif (options?.expire) {\n\t\t\targs.push('--expire', options.expire);\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\n\t\t\tconst after = await this.listWorktreePaths(repoPath);\n\n\t\t\t// Order matters (see `deleteWorktree`): unregister before emitting the repo-level change so any\n\t\t\t// listener that re-queries worktree-aware state sees the registry already updated.\n\t\t\tif (before != null && after != null) {\n\t\t\t\tfor (const path of before) {\n\t\t\t\t\tif (!after.has(path)) {\n\t\t\t\t\t\tthis.cache.unregisterRepoPath(path);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t}\n\t}\n\n\t/**\n\t * Raw worktree paths currently known to git (`worktree <path>` lines from `--porcelain`), normalized the\n\t * same way {@link deleteWorktree} does. A failed listing (`errors: 'ignore'`) yields an empty set rather\n\t * than throwing — used by `pruneWorktrees` to diff before/after, where a transient read failure must not\n\t * be mistaken for every worktree having vanished.\n\t */\n\tprivate async listWorktreePaths(repoPath: string): Promise<Set<string> | undefined> {\n\t\tconst result = await this.git.run({ cwd: repoPath, errors: 'ignore' }, 'worktree', 'list', '--porcelain');\n\t\t// A failed listing is not an empty one: read as empty, the after-prune one would unregister everything\n\t\tif (result.completion.status !== 'exited' || result.exitCode !== 0) return undefined;\n\n\t\tconst paths = new Set<string>();\n\t\tfor (const line of result.stdout.split('\\n')) {\n\t\t\tif (line.startsWith('worktree ')) {\n\t\t\t\tpaths.add(normalizePath(toFsPath(line.slice('worktree '.length).trim())));\n\t\t\t}\n\t\t}\n\t\treturn paths;\n\t}\n\n\t@debug()\n\tasync lockWorktree(repoPath: string, path: string | Uri, options?: { reason?: string }): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Locking worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst args = ['worktree', 'lock'];\n\t\tif (options?.reason) {\n\t\t\targs.push('--reason', options.reason);\n\t\t}\n\t\targs.push(normalizePath(toFsPath(path)));\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\t\t} finally {\n\t\t\t// A lock touches no worktree's HEAD, so no worktree's git results or merge targets\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktreeList');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unlockWorktree(repoPath: string, path: string | Uri): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Unlocking worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathStr = normalizePath(toFsPath(path));\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, 'worktree', 'unlock', pathStr);\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktreeList');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"worktrees.js","names":["basename","fs"],"sources":["../../../../git-cli/src/providers/worktrees.ts"],"sourcesContent":["import { exec } from 'child_process';\nimport { promises as fs } from 'fs';\nimport { join, resolve } from 'path';\nimport * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { WorktreeCreateError, WorktreeDeleteError } from '@gitlens/git/errors.js';\nimport type { GitBranch } from '@gitlens/git/models/branch.js';\nimport type { WorkspaceFolderResolver } from '@gitlens/git/models/worktree.js';\nimport { GitWorktree } from '@gitlens/git/models/worktree.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitWorktreesSubProvider } from '@gitlens/git/providers/worktrees.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { isWindows } from '@gitlens/utils/env/node/platform.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { basename, isDescendant, normalizePath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { CacheController } from '@gitlens/utils/promiseCache.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { mayWriteTracking } from '../exec/commandClassifier.js';\nimport type { Git, GitError } from '../exec/git.js';\nimport { getGitCommandError, GitErrors, isRunHookFailure } from '../exec/git.js';\nimport type { IndexRefresher } from '../exec/indexRefresh.js';\nimport { refreshIndexAfter } from '../exec/indexRefresh.js';\nimport { parseGitWorktrees } from '../parsers/worktreeParser.js';\n\n/** Extracts the lock reason from Git's `cannot remove a locked working tree` output, when it provides one */\nfunction getLockReason(ex: GitError): string | undefined {\n\treturn GitErrors.worktreeLockedReason.exec(ex.stderr || ex.stdout || ex.message || '')?.[1].trim() || undefined;\n}\n\n/**\n * The branch `git worktree add` says it created, from the `Preparing worktree (new branch '<name>')` line it writes to\n * stderr (git 2.17+, in English since every run sets `LC_ALL=C`)\n */\nfunction getNewWorktreeBranch(stderr: string | undefined): string | undefined {\n\treturn stderr ? /^Preparing worktree \\(new branch '(.+)'\\)$/m.exec(stderr)?.[1] : undefined;\n}\n\nconst unbornSha = /^0+$/;\n\n/**\n * Where `git worktree list` contradicts the branch list it was paired with, or `undefined` when they agree. `switched`\n * holds the worktrees whose checked-out branch differs from the one the branch list places there.\n */\nfunction findStaleBranches(\n\tworktrees: readonly GitWorktree[],\n\tbranches: readonly GitBranch[],\n\t/** Whether git says where each branch is checked out (`%(worktreepath)`); before it, only the current branch's is known */\n\tknowsPaths: boolean,\n): { switched: string[] } | undefined {\n\tif (!worktrees.length) return undefined;\n\n\tconst byName = new Map<string, GitBranch>();\n\tconst byPath = new Map<string, GitBranch>();\n\tfor (const b of branches) {\n\t\t// A detached HEAD's stand-in branch names no ref\n\t\tif (b.remote || b.detached) continue;\n\n\t\tbyName.set(b.name, b);\n\t\t// A rebasing branch's worktree lists as detached\n\t\tif (b.worktree && !b.rebasing) {\n\t\t\tbyPath.set(normalizePath(b.worktree.path), b);\n\t\t}\n\t}\n\n\t// Git places a branch checked out in several worktrees (`worktree add --force`) at only one of them\n\tconst listedBranches = new Map(worktrees.map(w => [w.path, w.branchName]));\n\n\tlet stale = false;\n\tconst switched: string[] = [];\n\tfor (const w of worktrees) {\n\t\t// A bare repository checks nothing out, though git places the branch its HEAD names there\n\t\tif (w.type === 'bare') {\n\t\t\tbyPath.delete(w.path);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst listed = byPath.get(w.path);\n\t\tif (listed != null) {\n\t\t\tbyPath.delete(w.path);\n\t\t\tif (listed.name !== w.branchName) {\n\t\t\t\tswitched.push(w.path);\n\t\t\t\tstale = true;\n\t\t\t}\n\t\t} else if (knowsPaths && w.branchName != null) {\n\t\t\t// Detached, or not yet a worktree, when the branches were read\n\t\t\tswitched.push(w.path);\n\t\t}\n\n\t\t// An unborn branch has no ref for the branch list to know\n\t\tif (w.branchName == null || !w.sha || unbornSha.test(w.sha)) continue;\n\n\t\tconst branch = byName.get(w.branchName);\n\t\tif (\n\t\t\tbranch == null ||\n\t\t\t(branch.sha != null && branch.sha !== w.sha) ||\n\t\t\tbranch.worktree === false ||\n\t\t\t(branch.worktree != null && listedBranches.get(normalizePath(branch.worktree.path)) !== w.branchName)\n\t\t) {\n\t\t\tstale = true;\n\t\t}\n\t}\n\n\t// A branch placed in a worktree that no longer lists it was removed or switched away\n\tif (byPath.size) {\n\t\tstale = true;\n\t}\n\n\treturn stale ? { switched: switched } : undefined;\n}\n\nexport class WorktreesGitSubProvider implements GitWorktreesSubProvider {\n\t/** Per common path, the read whose `git worktree list` hasn't started yet */\n\tprivate readonly _unspawnedReads = new Map<string, object>();\n\t/**\n\t * Per common path, the `git worktree list` output a fresh branch list still contradicted: a layout where git's two\n\t * listings never agree, which re-reading the branches again can't fix until the list changes\n\t */\n\tprivate readonly _lastingDisagreements = new Map<string, string>();\n\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t\t/**\n\t\t * Reads the absolute folders whose worktrees a repository's list leaves out, rejecting (or answering `undefined`)\n\t\t * when they can't be read; given only when folders are registered\n\t\t */\n\t\tprivate readonly readIgnoredWorktreeRoots?: (repoPath: string) => Promise<readonly string[] | undefined>,\n\t\t/** Refreshes the index of a worktree it just checked out */\n\t\tprivate readonly indexRefresher?: IndexRefresher,\n\t) {}\n\n\t/**\n\t * Creates a worktree (`git worktree add`). `runOptions` are spread into the underlying `git.run` call, so a\n\t * large checkout can run without the default command timeout (`{ timeout: 0 }`) and still be cancelled.\n\t */\n\t@debug()\n\tasync createWorktree(\n\t\trepoPath: string,\n\t\tpath: string,\n\t\toptions?: {\n\t\t\tcommitish?: string;\n\t\t\tcreateBranch?: string;\n\t\t\tdetach?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tnoTracking?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst args = ['worktree', 'add'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t}\n\t\tif (options?.createBranch) {\n\t\t\targs.push('-b', options.createBranch);\n\t\t}\n\t\tif (options?.createBranch && options.noTracking) {\n\t\t\targs.push('--no-track');\n\t\t}\n\t\tif (options?.detach) {\n\t\t\targs.push('--detach');\n\t\t}\n\t\targs.push(path);\n\t\tif (options?.commitish) {\n\t\t\targs.push(options.commitish);\n\t\t}\n\n\t\t// Without `-b`, git may still create a branch: from a remote branch of the commitish's name, or named after the\n\t\t// path when no commitish is given\n\t\tlet createdBranch = options?.createBranch;\n\t\t// A cancelled or timed-out run, or a host-rejected retry, leaves no output to name the branch git may have created\n\t\tlet mayHaveCreatedBranch = false;\n\t\ttry {\n\t\t\tconst run = () => this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\t\t\t// A relative path is the new worktree's location from `repoPath`, where git ran\n\t\t\tconst result = await refreshIndexAfter(this.indexRefresher, normalizePath(resolve(repoPath, path)), run);\n\t\t\tcreatedBranch ??= getNewWorktreeBranch(result.stderr);\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// `?.`: a host's index-lock retry hook may reject with anything, `undefined` included\n\t\t\tcreatedBranch ??= getNewWorktreeBranch((ex as GitError | undefined)?.stderr);\n\n\t\t\t// A cancelled or timed-out checkout, or a host-rejected index-lock retry, is not git refusing the worktree\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) {\n\t\t\t\tmayHaveCreatedBranch = createdBranch == null && !options?.detach;\n\t\t\t\tthrow ex;\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'worktree-create',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew WorktreeCreateError(\n\t\t\t\t\t\t{ reason: reason, gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex as GitError,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled add may already have created the branch (and its tracking in `.git/config`) or\n\t\t\t// the worktree directory.\n\t\t\t//\n\t\t\t// The tracking isn't announced as a `config` change, only evicted: git may also write repository-wide\n\t\t\t// keys (`extensions.relativeWorktrees` under `worktree.useRelativePaths`), so the write can't claim its\n\t\t\t// config change is confined to the new branch, and an unconfined one would refresh every worktree on each\n\t\t\t// add. The watcher's report of the file says what changed in it instead.\n\t\t\tif (createdBranch) {\n\t\t\t\t// Evict the cached base only — see `checkout -b` for why the persisted keys are left alone.\n\t\t\t\tthis.cache.deleteBaseBranchName(repoPath, createdBranch);\n\t\t\t\t// A branch git created on its own may track a remote branch, whatever the commitish looks like\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(\n\t\t\t\t\trepoPath,\n\t\t\t\t\t...(!options?.createBranch || mayWriteTracking(options.commitish, options.noTracking)\n\t\t\t\t\t\t? (['branches', 'config', 'worktrees'] as const)\n\t\t\t\t\t\t: (['branches', 'worktrees'] as const)),\n\t\t\t\t);\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(\n\t\t\t\t\trepoPath,\n\t\t\t\t\t['worktrees', 'worktreeHead', 'heads'],\n\t\t\t\t\t[`refs/heads/${createdBranch}`],\n\t\t\t\t);\n\t\t\t} else if (mayHaveCreatedBranch) {\n\t\t\t\t// Git creates the branch before checking it out, so a run cut short may have left one it never named\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'branches', 'config', 'worktrees');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead', 'heads']);\n\t\t\t} else {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t\t}\n\t\t}\n\t}\n\n\tasync createWorktreeWithResult(\n\t\trepoPath: string,\n\t\tpath: string,\n\t\toptions?: {\n\t\t\tcommitish?: string;\n\t\t\tcreateBranch?: string;\n\t\t\tdetach?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tnoTracking?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<GitWorktree | undefined> {\n\t\tawait this.createWorktree(repoPath, path, options, runOptions);\n\t\tconst normalized = normalizePath(path);\n\t\treturn this.getWorktree(\n\t\t\trepoPath,\n\t\t\tw => normalizePath(w.path) === normalized,\n\t\t\tundefined,\n\t\t\trunOptions?.cancellation,\n\t\t);\n\t}\n\n\t@debug({ quiet: true })\n\tasync getWorktree(\n\t\trepoPath: string,\n\t\tpredicate: (w: GitWorktree) => boolean,\n\t\toptions?: { force?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree | undefined> {\n\t\treturn (await this.getWorktrees(repoPath, options, cancellation)).find(predicate);\n\t}\n\n\t@debug({ quiet: true })\n\tasync getWorktrees(\n\t\trepoPath: string,\n\t\toptions?: { force?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree[]> {\n\t\t// A pending read that hasn't started `git worktree list` will see the state as of this call, so it is joined,\n\t\t// whether it was pending as the call started or is once the call would evict (another forced read's, say)\n\t\tlet force = options?.force === true && !this._unspawnedReads.has(this.cache.getCommonPath(repoPath));\n\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Displaying worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tif (force && this._unspawnedReads.has(this.cache.getCommonPath(repoPath))) {\n\t\t\tforce = false;\n\t\t}\n\n\t\treturn this.cache.getWorktrees(\n\t\t\trepoPath,\n\t\t\tasync (commonPath, cacheable, signal) => {\n\t\t\t\tconst unspawned = {};\n\t\t\t\tthis._unspawnedReads.set(commonPath, unspawned);\n\t\t\t\tconst onSpawned = () => {\n\t\t\t\t\tif (this._unspawnedReads.get(commonPath) === unspawned) {\n\t\t\t\t\t\tthis._unspawnedReads.delete(commonPath);\n\t\t\t\t\t}\n\t\t\t\t};\n\n\t\t\t\ttry {\n\t\t\t\t\treturn await this.readWorktrees(repoPath, commonPath, cacheable, signal ?? cancellation, onSpawned);\n\t\t\t\t} finally {\n\t\t\t\t\tonSpawned();\n\t\t\t\t}\n\t\t\t},\n\t\t\tforce ? { force: true } : undefined,\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async readWorktrees(\n\t\trepoPath: string,\n\t\tcommonPath: string,\n\t\tcacheable: CacheController,\n\t\tsignal: AbortSignal | undefined,\n\t\tonSpawn: () => void,\n\t): Promise<GitWorktree[]> {\n\t\t// Read beside the list, which it doesn't depend on. `commonPath` is the main worktree, not the git dir,\n\t\t// so the roots come from the repository's own git dir\n\t\tconst rootsRead = this.readIgnoredWorktreeRoots?.(repoPath).catch(() => undefined);\n\t\tconst [dataResult, branchesResult] = await Promise.allSettled([\n\t\t\tthis.git.run(\n\t\t\t\t{ cwd: commonPath, cancellation: signal, onSpawn: onSpawn },\n\t\t\t\t'worktree',\n\t\t\t\t'list',\n\t\t\t\t'--porcelain',\n\t\t\t),\n\t\t\tthis.provider.branches.getBranches(commonPath, undefined, signal),\n\t\t]);\n\n\t\tif (dataResult.status === 'rejected') {\n\t\t\t// Don't cache a bogus empty result for a transient command failure — retry on next access.\n\t\t\tcacheable.invalidate();\n\t\t}\n\n\t\tconst getWorkspaceFolder: WorkspaceFolderResolver | undefined = this.context.workspace\n\t\t\t? uri => {\n\t\t\t\t\tconst folder = this.context.workspace!.getFolder(uri.fsPath);\n\t\t\t\t\tif (folder == null) return undefined;\n\t\t\t\t\treturn { uri: fileUri(folder.path), name: basename(folder.path) };\n\t\t\t\t}\n\t\t\t: undefined;\n\n\t\tconst data = getSettledValue(dataResult)?.stdout;\n\t\tlet worktrees = parseGitWorktrees(\n\t\t\tdata,\n\t\t\tcommonPath,\n\t\t\tgetSettledValue(branchesResult)?.values ?? [],\n\t\t\tgetWorkspaceFolder,\n\t\t);\n\n\t\t// The branches come from the cache, which can lag the list just read (a forced read pairs a fresh list with\n\t\t// them). Where the list contradicts them it proves them stale, so they are re-read, once\n\t\tconst knowsPaths = await this.git.supports('git:for-each-ref:worktreePath');\n\t\tconst stale =\n\t\t\tbranchesResult.status === 'fulfilled'\n\t\t\t\t? findStaleBranches(worktrees, branchesResult.value.values, knowsPaths)\n\t\t\t\t: undefined;\n\t\tif (stale == null) {\n\t\t\tthis._lastingDisagreements.delete(commonPath);\n\t\t} else if (this._lastingDisagreements.get(commonPath) !== data) {\n\t\t\tthis.context.hooks?.cache?.onReset?.(commonPath, 'branches');\n\t\t\tfor (const path of stale.switched) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(path, 'branch');\n\t\t\t}\n\n\t\t\tlet branches: GitBranch[] | undefined;\n\t\t\ttry {\n\t\t\t\t({ values: branches } = await this.provider.branches.getBranches(commonPath, undefined, signal));\n\t\t\t} catch {\n\t\t\t\t// Keep the branches matched from the stale list, but not in the cache\n\t\t\t\tcacheable.invalidate();\n\t\t\t}\n\n\t\t\tif (branches != null) {\n\t\t\t\tworktrees = parseGitWorktrees(data, commonPath, branches, getWorkspaceFolder);\n\t\t\t\tif (data != null && findStaleBranches(worktrees, branches, knowsPaths) != null) {\n\t\t\t\t\tthis._lastingDisagreements.set(commonPath, data);\n\t\t\t\t}\n\t\t\t\t// The host's views show the branches the watcher missed a change of; which moved is unknown. Only the\n\t\t\t\t// host hears it: announced as a write of core's, the watch layer would take an outside `heads` report\n\t\t\t\t// arriving meanwhile for its echo and drop it, though nothing of the kind was evicted for it\n\t\t\t\tfor (const path of new Set([commonPath, ...this.cache.getWorktreePaths(commonPath)])) {\n\t\t\t\t\tthis.provider.notifyHost(path, ['heads']);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (rootsRead != null) {\n\t\t\tconst roots = await rootsRead;\n\t\t\tif (roots == null) {\n\t\t\t\t// The folders couldn't be read: an unfiltered list would keep ignored worktrees in the shared\n\t\t\t\t// cache until the next change\n\t\t\t\tcacheable.invalidate();\n\t\t\t} else if (roots.length) {\n\t\t\t\tworktrees = worktrees.filter(w => !roots.some(root => isDescendant(normalizePath(w.path), root)));\n\t\t\t}\n\t\t}\n\n\t\t// Older git prints a bare `locked` even when a reason exists; recover it from the admin dir\n\t\tif (await this.git.supports('git:worktree:list:lock-reason')) return worktrees;\n\n\t\treturn Promise.all(worktrees.map(w => this.withLockReason(w)));\n\t}\n\n\tprivate async withLockReason(worktree: GitWorktree): Promise<GitWorktree> {\n\t\tif (worktree.locked !== true || worktree.isDefault || worktree.type === 'bare') return worktree;\n\n\t\ttry {\n\t\t\t// A linked worktree's `.git` is a file: `gitdir: <admin dir>`, relative to the worktree when not absolute\n\t\t\tconst dotGit = join(worktree.uri.fsPath, '.git');\n\t\t\tconst match = /^gitdir:\\s*(.+?)\\s*$/m.exec(await fs.readFile(dotGit, 'utf8'));\n\t\t\tif (match == null) return worktree;\n\n\t\t\tconst reason = (await fs.readFile(join(resolve(worktree.uri.fsPath, match[1]), 'locked'), 'utf8')).trim();\n\t\t\tif (!reason) return worktree;\n\n\t\t\treturn new GitWorktree(\n\t\t\t\tworktree.isDefault,\n\t\t\t\tworktree.type,\n\t\t\t\tworktree.repoPath,\n\t\t\t\tworktree.uri,\n\t\t\t\treason,\n\t\t\t\tworktree.prunable,\n\t\t\t\tworktree.sha,\n\t\t\t\tworktree.branch,\n\t\t\t\tworktree.workspaceFolder,\n\t\t\t\tworktree.branchName,\n\t\t\t);\n\t\t} catch {\n\t\t\treturn worktree;\n\t\t}\n\t}\n\n\t@debug({ quiet: true })\n\tgetWorktreesDefaultUri(repoPath: string): Uri | undefined {\n\t\treturn this.context.workspace?.getWorktreeDefaultUri?.(repoPath);\n\t}\n\n\t/**\n\t * Deletes a worktree (`git worktree remove`). Pass `force: 'locked'` to also override a locked worktree.\n\t *\n\t * `runOptions` are spread into the underlying `git.run` call (e.g. `{ timeout: 0 }` for a large worktree\n\t * whose removal may exceed the default command timeout).\n\t *\n\t * On failure, the thrown {@link WorktreeDeleteError}'s `original` property carries the raw\n\t * {@link GitError} (stderr/stdout/exit code) untouched — a caller that needs to classify a\n\t * platform-specific failure (e.g. a Windows file-lock retry) can read it directly rather than parsing\n\t * the typed error's message.\n\t */\n\t@debug()\n\tasync deleteWorktree(\n\t\trepoPath: string,\n\t\tpath: string | Uri,\n\t\toptions?: { force?: boolean | 'locked' },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst scope = getScopedLogger();\n\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Deleting worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst args = ['worktree', 'remove'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t\t// Git requires a second `--force` to remove a locked worktree\n\t\t\tif (options.force === 'locked') {\n\t\t\t\targs.push('--force');\n\t\t\t}\n\t\t}\n\n\t\tconst pathStr = normalizePath(toFsPath(path));\n\t\targs.push(pathStr);\n\n\t\tlet deleted = false;\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args);\n\t\t\tdeleted = true;\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// A cancelled or timed-out removal (`runOptions.cancellation`/`timeout`), or a host-rejected index-lock\n\t\t\t// retry, is not git refusing it, and wrapping it would hand the caller a `WorktreeDeleteError` whose\n\t\t\t// `original` is no `GitError` at all\n\t\t\tif (isCancellationError(ex) || isRunHookFailure(ex)) throw ex;\n\n\t\t\tconst gitError = getGitCommandError(\n\t\t\t\t'worktree-delete',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew WorktreeDeleteError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treason: reason,\n\t\t\t\t\t\t\tlockReason: reason === 'locked' ? getLockReason(ex as GitError) : undefined,\n\t\t\t\t\t\t\tgitCommand: { repoPath: repoPath, args: args },\n\t\t\t\t\t\t},\n\t\t\t\t\t\tex as GitError,\n\t\t\t\t\t),\n\t\t\t);\n\n\t\t\tif (gitError.details.reason === 'directoryNotEmpty') {\n\t\t\t\tscope?.warn(\n\t\t\t\t\t`Failed to fully delete worktree '${pathStr}' because it is not empty. Attempting to delete it manually.`,\n\t\t\t\t);\n\t\t\t\ttry {\n\t\t\t\t\tawait fs.rm(pathStr, { force: true, recursive: true });\n\t\t\t\t\tdeleted = true;\n\t\t\t\t\treturn;\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tif (isWindows) {\n\t\t\t\t\t\tconst match = /EPERM: operation not permitted, unlink '(.*?)'/i.exec((ex as GitError).message);\n\t\t\t\t\t\tif (match != null) {\n\t\t\t\t\t\t\tscope?.warn(\n\t\t\t\t\t\t\t\t`Failed to manually delete '${pathStr}' because it is in use. Attempting to forcefully delete it.`,\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t\t// Windows-specific: `del` via cmd.exe to force-remove a locked symlink.\n\t\t\t\t\t\t\t// Node's fs.rm/unlink fails with EPERM when the symlink target is in use.\n\t\t\t\t\t\t\tfunction deleteInUseSymlink(symlink: string) {\n\t\t\t\t\t\t\t\treturn new Promise((resolve, reject) => {\n\t\t\t\t\t\t\t\t\texec(`del \"${symlink}\"`, (ex, stdout, stderr) => {\n\t\t\t\t\t\t\t\t\t\tif (ex) {\n\t\t\t\t\t\t\t\t\t\t\treject(ex instanceof Error ? ex : new Error(String(ex)));\n\t\t\t\t\t\t\t\t\t\t} else if (stderr) {\n\t\t\t\t\t\t\t\t\t\t\treject(new Error(stderr));\n\t\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t\tresolve(stdout);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst [, file] = match;\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tawait deleteInUseSymlink(file);\n\t\t\t\t\t\t\t\tawait fs.rm(pathStr, { force: true, recursive: true, maxRetries: 1, retryDelay: 1 });\n\t\t\t\t\t\t\t\tdeleted = true;\n\t\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t\tscope?.error(ex, `Failed to forcefully delete '${pathStr}' because it is in use.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow gitError;\n\t\t} finally {\n\t\t\tif (deleted) {\n\t\t\t\t// Clean up Cache registry + per-worktree cache entries for the deleted worktree.\n\t\t\t\t// Order matters: unregister before emitting the repo-level change so any listener\n\t\t\t\t// that re-queries worktree-aware state sees the registry already updated.\n\t\t\t\tthis.cache.unregisterRepoPath(pathStr);\n\t\t\t}\n\t\t\t// A failed or cancelled removal may already have taken the worktree's files or admin entry\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync pruneWorktrees(repoPath: string, options?: { expire?: string }): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Pruning worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst before = await this.listWorktreePaths(repoPath);\n\n\t\tconst args = ['worktree', 'prune'];\n\t\tif (options?.expire) {\n\t\t\targs.push('--expire', options.expire);\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\n\t\t\tconst after = await this.listWorktreePaths(repoPath);\n\n\t\t\t// Order matters (see `deleteWorktree`): unregister before emitting the repo-level change so any\n\t\t\t// listener that re-queries worktree-aware state sees the registry already updated.\n\t\t\tif (before != null && after != null) {\n\t\t\t\tfor (const path of before) {\n\t\t\t\t\tif (!after.has(path)) {\n\t\t\t\t\t\tthis.cache.unregisterRepoPath(path);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees', 'worktreeHead']);\n\t\t}\n\t}\n\n\t/**\n\t * Raw worktree paths currently known to git (`worktree <path>` lines from `--porcelain`), normalized the\n\t * same way {@link deleteWorktree} does. A failed listing (`errors: 'ignore'`) yields an empty set rather\n\t * than throwing — used by `pruneWorktrees` to diff before/after, where a transient read failure must not\n\t * be mistaken for every worktree having vanished.\n\t */\n\tprivate async listWorktreePaths(repoPath: string): Promise<Set<string> | undefined> {\n\t\tconst result = await this.git.run({ cwd: repoPath, errors: 'ignore' }, 'worktree', 'list', '--porcelain');\n\t\t// A failed listing is not an empty one: read as empty, the after-prune one would unregister everything\n\t\tif (result.completion.status !== 'exited' || result.exitCode !== 0) return undefined;\n\n\t\tconst paths = new Set<string>();\n\t\tfor (const line of result.stdout.split('\\n')) {\n\t\t\tif (line.startsWith('worktree ')) {\n\t\t\t\tpaths.add(normalizePath(toFsPath(line.slice('worktree '.length).trim())));\n\t\t\t}\n\t\t}\n\t\treturn paths;\n\t}\n\n\t@debug()\n\tasync lockWorktree(repoPath: string, path: string | Uri, options?: { reason?: string }): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Locking worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst args = ['worktree', 'lock'];\n\t\tif (options?.reason) {\n\t\t\targs.push('--reason', options.reason);\n\t\t}\n\t\targs.push(normalizePath(toFsPath(path)));\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\t\t} finally {\n\t\t\t// A lock touches no worktree's HEAD, so no worktree's git results or merge targets\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktreeList');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unlockWorktree(repoPath: string, path: string | Uri): Promise<void> {\n\t\tawait this.git.ensureSupports('git:worktrees', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Unlocking worktrees requires a newer version of Git (>= {0}) than is currently installed ({1}). Please install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathStr = normalizePath(toFsPath(path));\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, 'worktree', 'unlock', pathStr);\n\t\t} finally {\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktreeList');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
@@ -28,6 +28,8 @@ export interface CliGitServiceOptions {
28
28
  cache?: CliGitProviderOptions['cache'];
29
29
  /** Folders, relative to a repository's common git dir, whose worktrees core acts as if didn't exist */
30
30
  ignoredWorktreeFolders?: CliGitProviderOptions['ignoredWorktreeFolders'];
31
+ /** Refreshes a checkout's index after core's own writes rewrote it (see `CliGitProviderOptions`); off by default */
32
+ refreshIndexAfterWrites?: CliGitProviderOptions['refreshIndexAfterWrites'];
31
33
  /**
32
34
  * Filesystem watching provider. When provided, the {@link GitService}
33
35
  * will watch repositories for changes (file creates, edits, deletes).
@@ -35,7 +35,8 @@ function createCliGitService(options) {
35
35
  locator,
36
36
  gitOptions: options.gitOptions,
37
37
  cache: options.cache,
38
- ignoredWorktreeFolders: options.ignoredWorktreeFolders
38
+ ignoredWorktreeFolders: options.ignoredWorktreeFolders,
39
+ refreshIndexAfterWrites: options.refreshIndexAfterWrites
39
40
  });
40
41
  service.register(provider, () => true);
41
42
  service.watchService?.onDidChangeWorkingTree((repoPath) => provider.cache.onWorkingTreeChanged(repoPath));
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","names":[],"sources":["../../../git-cli/src/service.ts"],"sourcesContent":["import { GitService } from '@gitlens/git/service.js';\nimport type { FileWatchingProvider } from '@gitlens/git/watching/provider.js';\nimport type { WatchPollingOptions } from '@gitlens/git/watching/watchService.js';\nimport type { WorktreeSummaryServiceOptions } from '@gitlens/git/watching/worktreeSummary.js';\nimport { fileUri } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderOptions } from './cliGitProvider.js';\nimport { CliGitProvider } from './cliGitProvider.js';\nimport type { GitLocation } from './exec/locator.js';\nimport { findGitPath } from './exec/locator.js';\n\n/**\n * Options for {@link createCliGitService}.\n */\nexport interface CliGitServiceOptions {\n\t/**\n\t * Path(s) to the git binary.\n\t * Auto-detected if omitted (searches PATH, platform-specific locations).\n\t * Ignored when {@link locator} is provided.\n\t */\n\tgitPath?: string | string[];\n\n\t/**\n\t * Custom git binary resolver. When provided, used instead of the\n\t * default `findGitPath(gitPath)` lookup.\n\t */\n\tlocator?: () => Promise<GitLocation>;\n\n\t/** Host-provided context hooks (cache events, workspace, integrations, telemetry, fs) */\n\tcontext: CliGitProviderOptions['context'];\n\n\t/** Git execution options passed through to the underlying Git executor */\n\tgitOptions?: CliGitProviderOptions['gitOptions'];\n\n\t/** Use an existing Cache instance, or one will be created */\n\tcache?: CliGitProviderOptions['cache'];\n\n\t/** Folders, relative to a repository's common git dir, whose worktrees core acts as if didn't exist */\n\tignoredWorktreeFolders?: CliGitProviderOptions['ignoredWorktreeFolders'];\n\n\t/**\n\t * Filesystem watching provider. When provided, the {@link GitService}\n\t * will watch repositories for changes (file creates, edits, deletes).\n\t */\n\twatchingProvider?: FileWatchingProvider;\n\n\t/**\n\t * Polls in place of (or beside) the watchers {@link watchingProvider} reports it can't trust. When omitted, no\n\t * watcher is asked.\n\t */\n\twatchPolling?: WatchPollingOptions;\n\n\t/** For tests only; production never passes it (see `WorktreeSummaryServiceOptions.verifyBaseRemeasure`) */\n\tverifyBaseRemeasure?: WorktreeSummaryServiceOptions['verifyBaseRemeasure'];\n}\n\n/**\n * Creates a ready-to-use {@link GitService} backed by the CLI git provider.\n *\n * This is the primary entry point for standalone (non-VS Code) consumers\n * of the `@gitlens/git-cli` library. It creates a singleton {@link GitService},\n * wires up a {@link CliGitProvider}, and registers it for all repository paths.\n *\n * @example\n * ```typescript\n * const git = createCliGitService({ context: {} });\n *\n * const repo = git.forRepo('/path/to/repo')!;\n * const branches = await repo.branches.getBranches();\n * const status = await repo.status.getStatus();\n * await repo.ops!.fetch({ remote: 'origin' });\n *\n * git.dispose(); // cleans up provider, cache, and module-level state\n * ```\n */\nexport function createCliGitService(options: CliGitServiceOptions): GitService {\n\tconst service = GitService.createSingleton(options.watchingProvider, {\n\t\twatchPolling: options.watchPolling,\n\t\tverifyBaseRemeasure: options.verifyBaseRemeasure,\n\t\t// The host's file system reads the shared `.git/config` the watch service compares reports of\n\t\treadFile: path => options.context.fs.readFile(fileUri(path)),\n\t\t// And lists the directory the admin entries of its worktrees are in\n\t\treadDirectory: path => options.context.fs.readDirectory(fileUri(path)),\n\t});\n\n\tconst locator = options.locator ?? (() => findGitPath(options.gitPath ?? null));\n\tconst provider = new CliGitProvider({\n\t\tcontext: options.context,\n\t\tlocator: locator,\n\t\tgitOptions: options.gitOptions,\n\t\tcache: options.cache,\n\t\tignoredWorktreeFolders: options.ignoredWorktreeFolders,\n\t});\n\n\tservice.register(provider, () => true);\n\n\t// Advance the provider cache's status generation clock from the watch session's global events — the standalone\n\t// analogue of what the VS Code host wires in `GitProviderService`. Without this, a consumer that passes a\n\t// `watchingProvider` and drives watch sessions gets FS events but a FROZEN clock, so `dedupeByStatusGeneration`\n\t// degrades to the pre-change/post-change stale-join this branch exists to fix. Standalone has no `Repository`\n\t// models, so there are no force-fired `closed`/`lastFetched` bypassing the session for the global repo event to\n\t// miss. Subscriptions are torn down with the service (its `watchService`'s emitters are disposed on dispose).\n\tservice.watchService?.onDidChangeWorkingTree(repoPath => provider.cache.onWorkingTreeChanged(repoPath));\n\t// Announced kinds were evicted when core announced its write; evicting them again would discard what the host\n\t// re-read since\n\tservice.watchService?.onDidChangeRepository(e => {\n\t\tconst changes = e.getUnannouncedChanges();\n\t\tif (changes.length) {\n\t\t\tprovider.cache.onRepositoryChanged(e.repoPath, changes);\n\t\t}\n\t});\n\t// FETCH_HEAD maps to no session change, and there's no `Repository` model here to force-fire `lastFetched` (as\n\t// the VS Code host does), so bridge it straight to the cache or the last-fetched time is never re-read.\n\tservice.watchService?.onDidChangeFetchHead(repoPath =>\n\t\tprovider.cache.onRepositoryChanged(repoPath, ['lastFetched']),\n\t);\n\treturn service;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA0EA,SAAgB,oBAAoB,SAA2C;CAC9E,MAAM,UAAU,WAAW,gBAAgB,QAAQ,kBAAkB;EACpE,cAAc,QAAQ;EACtB,qBAAqB,QAAQ;EAE7B,WAAU,SAAQ,QAAQ,QAAQ,GAAG,SAAS,QAAQ,IAAI,CAAC;EAE3D,gBAAe,SAAQ,QAAQ,QAAQ,GAAG,cAAc,QAAQ,IAAI,CAAC;CACtE,CAAC;CAED,MAAM,UAAU,QAAQ,kBAAkB,YAAY,QAAQ,WAAW,IAAI;CAC7E,MAAM,WAAW,IAAI,eAAe;EACnC,SAAS,QAAQ;EACR;EACT,YAAY,QAAQ;EACpB,OAAO,QAAQ;EACf,wBAAwB,QAAQ;CACjC,CAAC;CAED,QAAQ,SAAS,gBAAgB,IAAI;CAQrC,QAAQ,cAAc,wBAAuB,aAAY,SAAS,MAAM,qBAAqB,QAAQ,CAAC;CAGtG,QAAQ,cAAc,uBAAsB,MAAK;EAChD,MAAM,UAAU,EAAE,sBAAsB;EACxC,IAAI,QAAQ,QACX,SAAS,MAAM,oBAAoB,EAAE,UAAU,OAAO;CAExD,CAAC;CAGD,QAAQ,cAAc,sBAAqB,aAC1C,SAAS,MAAM,oBAAoB,UAAU,CAAC,aAAa,CAAC,CAC7D;CACA,OAAO;AACR"}
1
+ {"version":3,"file":"service.js","names":[],"sources":["../../../git-cli/src/service.ts"],"sourcesContent":["import { GitService } from '@gitlens/git/service.js';\nimport type { FileWatchingProvider } from '@gitlens/git/watching/provider.js';\nimport type { WatchPollingOptions } from '@gitlens/git/watching/watchService.js';\nimport type { WorktreeSummaryServiceOptions } from '@gitlens/git/watching/worktreeSummary.js';\nimport { fileUri } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderOptions } from './cliGitProvider.js';\nimport { CliGitProvider } from './cliGitProvider.js';\nimport type { GitLocation } from './exec/locator.js';\nimport { findGitPath } from './exec/locator.js';\n\n/**\n * Options for {@link createCliGitService}.\n */\nexport interface CliGitServiceOptions {\n\t/**\n\t * Path(s) to the git binary.\n\t * Auto-detected if omitted (searches PATH, platform-specific locations).\n\t * Ignored when {@link locator} is provided.\n\t */\n\tgitPath?: string | string[];\n\n\t/**\n\t * Custom git binary resolver. When provided, used instead of the\n\t * default `findGitPath(gitPath)` lookup.\n\t */\n\tlocator?: () => Promise<GitLocation>;\n\n\t/** Host-provided context hooks (cache events, workspace, integrations, telemetry, fs) */\n\tcontext: CliGitProviderOptions['context'];\n\n\t/** Git execution options passed through to the underlying Git executor */\n\tgitOptions?: CliGitProviderOptions['gitOptions'];\n\n\t/** Use an existing Cache instance, or one will be created */\n\tcache?: CliGitProviderOptions['cache'];\n\n\t/** Folders, relative to a repository's common git dir, whose worktrees core acts as if didn't exist */\n\tignoredWorktreeFolders?: CliGitProviderOptions['ignoredWorktreeFolders'];\n\n\t/** Refreshes a checkout's index after core's own writes rewrote it (see `CliGitProviderOptions`); off by default */\n\trefreshIndexAfterWrites?: CliGitProviderOptions['refreshIndexAfterWrites'];\n\n\t/**\n\t * Filesystem watching provider. When provided, the {@link GitService}\n\t * will watch repositories for changes (file creates, edits, deletes).\n\t */\n\twatchingProvider?: FileWatchingProvider;\n\n\t/**\n\t * Polls in place of (or beside) the watchers {@link watchingProvider} reports it can't trust. When omitted, no\n\t * watcher is asked.\n\t */\n\twatchPolling?: WatchPollingOptions;\n\n\t/** For tests only; production never passes it (see `WorktreeSummaryServiceOptions.verifyBaseRemeasure`) */\n\tverifyBaseRemeasure?: WorktreeSummaryServiceOptions['verifyBaseRemeasure'];\n}\n\n/**\n * Creates a ready-to-use {@link GitService} backed by the CLI git provider.\n *\n * This is the primary entry point for standalone (non-VS Code) consumers\n * of the `@gitlens/git-cli` library. It creates a singleton {@link GitService},\n * wires up a {@link CliGitProvider}, and registers it for all repository paths.\n *\n * @example\n * ```typescript\n * const git = createCliGitService({ context: {} });\n *\n * const repo = git.forRepo('/path/to/repo')!;\n * const branches = await repo.branches.getBranches();\n * const status = await repo.status.getStatus();\n * await repo.ops!.fetch({ remote: 'origin' });\n *\n * git.dispose(); // cleans up provider, cache, and module-level state\n * ```\n */\nexport function createCliGitService(options: CliGitServiceOptions): GitService {\n\tconst service = GitService.createSingleton(options.watchingProvider, {\n\t\twatchPolling: options.watchPolling,\n\t\tverifyBaseRemeasure: options.verifyBaseRemeasure,\n\t\t// The host's file system reads the shared `.git/config` the watch service compares reports of\n\t\treadFile: path => options.context.fs.readFile(fileUri(path)),\n\t\t// And lists the directory the admin entries of its worktrees are in\n\t\treadDirectory: path => options.context.fs.readDirectory(fileUri(path)),\n\t});\n\n\tconst locator = options.locator ?? (() => findGitPath(options.gitPath ?? null));\n\tconst provider = new CliGitProvider({\n\t\tcontext: options.context,\n\t\tlocator: locator,\n\t\tgitOptions: options.gitOptions,\n\t\tcache: options.cache,\n\t\tignoredWorktreeFolders: options.ignoredWorktreeFolders,\n\t\trefreshIndexAfterWrites: options.refreshIndexAfterWrites,\n\t});\n\n\tservice.register(provider, () => true);\n\n\t// Advance the provider cache's status generation clock from the watch session's global events — the standalone\n\t// analogue of what the VS Code host wires in `GitProviderService`. Without this, a consumer that passes a\n\t// `watchingProvider` and drives watch sessions gets FS events but a FROZEN clock, so `dedupeByStatusGeneration`\n\t// degrades to the pre-change/post-change stale-join this branch exists to fix. Standalone has no `Repository`\n\t// models, so there are no force-fired `closed`/`lastFetched` bypassing the session for the global repo event to\n\t// miss. Subscriptions are torn down with the service (its `watchService`'s emitters are disposed on dispose).\n\tservice.watchService?.onDidChangeWorkingTree(repoPath => provider.cache.onWorkingTreeChanged(repoPath));\n\t// Announced kinds were evicted when core announced its write; evicting them again would discard what the host\n\t// re-read since\n\tservice.watchService?.onDidChangeRepository(e => {\n\t\tconst changes = e.getUnannouncedChanges();\n\t\tif (changes.length) {\n\t\t\tprovider.cache.onRepositoryChanged(e.repoPath, changes);\n\t\t}\n\t});\n\t// FETCH_HEAD maps to no session change, and there's no `Repository` model here to force-fire `lastFetched` (as\n\t// the VS Code host does), so bridge it straight to the cache or the last-fetched time is never re-read.\n\tservice.watchService?.onDidChangeFetchHead(repoPath =>\n\t\tprovider.cache.onRepositoryChanged(repoPath, ['lastFetched']),\n\t);\n\treturn service;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA6EA,SAAgB,oBAAoB,SAA2C;CAC9E,MAAM,UAAU,WAAW,gBAAgB,QAAQ,kBAAkB;EACpE,cAAc,QAAQ;EACtB,qBAAqB,QAAQ;EAE7B,WAAU,SAAQ,QAAQ,QAAQ,GAAG,SAAS,QAAQ,IAAI,CAAC;EAE3D,gBAAe,SAAQ,QAAQ,QAAQ,GAAG,cAAc,QAAQ,IAAI,CAAC;CACtE,CAAC;CAED,MAAM,UAAU,QAAQ,kBAAkB,YAAY,QAAQ,WAAW,IAAI;CAC7E,MAAM,WAAW,IAAI,eAAe;EACnC,SAAS,QAAQ;EACR;EACT,YAAY,QAAQ;EACpB,OAAO,QAAQ;EACf,wBAAwB,QAAQ;EAChC,yBAAyB,QAAQ;CAClC,CAAC;CAED,QAAQ,SAAS,gBAAgB,IAAI;CAQrC,QAAQ,cAAc,wBAAuB,aAAY,SAAS,MAAM,qBAAqB,QAAQ,CAAC;CAGtG,QAAQ,cAAc,uBAAsB,MAAK;EAChD,MAAM,UAAU,EAAE,sBAAsB;EACxC,IAAI,QAAQ,QACX,SAAS,MAAM,oBAAoB,EAAE,UAAU,OAAO;CAExD,CAAC;CAGD,QAAQ,cAAc,sBAAqB,aAC1C,SAAS,MAAM,oBAAoB,UAAU,CAAC,aAAa,CAAC,CAC7D;CACA,OAAO;AACR"}
@@ -1,7 +1,7 @@
1
1
  import { join } from "path";
2
2
  import { mkdir, readFile, readdir, unlink, writeFile } from "fs/promises";
3
- import { kill, ppid } from "process";
4
3
  import { tmpdir } from "os";
4
+ import { kill, ppid } from "process";
5
5
  //#region ../ipc/src/discovery.ts
6
6
  /**
7
7
  * Directory scanned by `gk` binaries (and `@gitkraken/core-gitlens` consumers) for the
@@ -1,7 +1,7 @@
1
1
  import { basename, dirname, join } from "path";
2
- import { createReadStream } from "fs";
3
- import { open, readFile, readdir as readdir$1, stat } from "fs/promises";
2
+ import { open, readFile, readdir, stat } from "fs/promises";
4
3
  import { homedir } from "os";
4
+ import { createReadStream } from "fs";
5
5
  import { createInterface } from "readline";
6
6
  //#region ../plus/agents/src/providers/claudeCodeTranscript.ts
7
7
  /** Bytes read from each end of a transcript when summarizing. Titles and prompts cluster at both
@@ -269,7 +269,7 @@ var ClaudeCodeTranscriptReader = class {
269
269
  const cached = this._names.get(dir);
270
270
  if (cached != null && Date.now() - cached.resolvedAt < listingCacheTtlMs) return cached.names;
271
271
  const gen = this._listingGen;
272
- const names = (await readdir$1(dir, { withFileTypes: true })).filter((d) => d.isFile() && d.name.endsWith(".jsonl")).map((d) => d.name);
272
+ const names = (await readdir(dir, { withFileTypes: true })).filter((d) => d.isFile() && d.name.endsWith(".jsonl")).map((d) => d.name);
273
273
  if (gen === this._listingGen) this._names.set(dir, {
274
274
  names,
275
275
  resolvedAt: Date.now()
@@ -283,7 +283,7 @@ var ClaudeCodeTranscriptReader = class {
283
283
  if (cached != null && Date.now() - cached.resolvedAt < listingCacheTtlMs) return cached.dirs;
284
284
  const gen = this._listingGen;
285
285
  const root = this.getProjectsRoot();
286
- const dirs = (await readdir$1(root, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => join(root, d.name));
286
+ const dirs = (await readdir(root, { withFileTypes: true })).filter((d) => d.isDirectory()).map((d) => join(root, d.name));
287
287
  if (gen === this._listingGen) this._projectDirs = {
288
288
  dirs,
289
289
  resolvedAt: Date.now()
@@ -487,7 +487,7 @@ var ClaudeCodeTranscriptReader = class {
487
487
  if (await directoryExists(exact)) return exact;
488
488
  let dirs;
489
489
  try {
490
- dirs = await readdir$1(root);
490
+ dirs = await readdir(root);
491
491
  } catch (ex) {
492
492
  if (!isMissingEntry(ex)) throw ex;
493
493
  return;
@@ -506,7 +506,7 @@ var ClaudeCodeTranscriptReader = class {
506
506
  const root = this.getProjectsRoot();
507
507
  let dirs;
508
508
  try {
509
- dirs = await readdir$1(root);
509
+ dirs = await readdir(root);
510
510
  } catch (ex) {
511
511
  if (!isMissingEntry(ex)) throw ex;
512
512
  return;