@gitkraken/core-gitlens 0.11.1 → 0.13.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.
- package/CHANGELOG.md +84 -1
- package/dist/git/cache.d.ts +84 -29
- package/dist/git/cache.js +188 -54
- package/dist/git/cache.js.map +1 -1
- package/dist/git/features.d.ts +1 -1
- package/dist/git/features.js +4 -0
- package/dist/git/features.js.map +1 -1
- package/dist/git/models/branch.d.ts +15 -2
- package/dist/git/models/branch.js +27 -5
- package/dist/git/models/branch.js.map +1 -1
- package/dist/git/models/issue.d.ts +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/models/status.js +1 -1
- package/dist/git/models/worktree.d.ts +4 -1
- package/dist/git/models/worktree.js +4 -2
- package/dist/git/models/worktree.js.map +1 -1
- package/dist/git/providers/branches.d.ts +73 -8
- package/dist/git/providers/pausedOperations.d.ts +6 -0
- package/dist/git/providers/provider.d.ts +34 -2
- package/dist/git/providers/status.d.ts +8 -2
- package/dist/git/remotes/azure-devops.js +61 -53
- package/dist/git/remotes/azure-devops.js.map +1 -1
- package/dist/git/service.d.ts +8 -5
- package/dist/git/service.js +16 -8
- package/dist/git/service.js.map +1 -1
- package/dist/git/utils/branch.utils.d.ts +8 -1
- package/dist/git/utils/branch.utils.js +30 -1
- package/dist/git/utils/branch.utils.js.map +1 -1
- package/dist/git/utils/issue.utils.d.ts +3 -1
- package/dist/git/utils/issue.utils.js +5 -1
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/watching/changeEvent.d.ts +13 -2
- package/dist/git/watching/changeEvent.js +17 -3
- package/dist/git/watching/changeEvent.js.map +1 -1
- package/dist/git/watching/gitDirPoller.d.ts +111 -0
- package/dist/git/watching/gitDirPoller.js +266 -0
- package/dist/git/watching/gitDirPoller.js.map +1 -0
- package/dist/git/watching/provider.d.ts +16 -0
- package/dist/git/watching/watchGroup.d.ts +40 -4
- package/dist/git/watching/watchGroup.js +143 -17
- package/dist/git/watching/watchGroup.js.map +1 -1
- package/dist/git/watching/watchService.d.ts +70 -1
- package/dist/git/watching/watchService.js +158 -13
- package/dist/git/watching/watchService.js.map +1 -1
- package/dist/git/watching/watchSession.d.ts +44 -0
- package/dist/git/watching/watchSession.js +91 -6
- package/dist/git/watching/watchSession.js.map +1 -1
- package/dist/git/watching/watcherPatterns.d.ts +21 -0
- package/dist/git/watching/watcherPatterns.js +67 -1
- package/dist/git/watching/watcherPatterns.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +34 -7
- package/dist/git/watching/worktreeSummary.js +39 -12
- package/dist/git/watching/worktreeSummary.js.map +1 -1
- package/dist/git-cli/cliGitProvider.d.ts +34 -2
- package/dist/git-cli/cliGitProvider.js +119 -17
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/commandClassifier.d.ts +15 -0
- package/dist/git-cli/exec/commandClassifier.js +48 -2
- package/dist/git-cli/exec/commandClassifier.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +15 -3
- package/dist/git-cli/exec/git.js +38 -17
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +2 -0
- package/dist/git-cli/exec/gitQueue.js +2 -1
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/exec/indexLock.d.ts +38 -0
- package/dist/git-cli/exec/indexLock.js +150 -0
- package/dist/git-cli/exec/indexLock.js.map +1 -0
- package/dist/git-cli/parsers/worktreeParser.js +42 -2
- package/dist/git-cli/parsers/worktreeParser.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +109 -10
- package/dist/git-cli/providers/branches.js +624 -131
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/config.d.ts +9 -5
- package/dist/git-cli/providers/config.js +60 -27
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +17 -0
- package/dist/git-cli/providers/operations.js +153 -96
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.d.ts +8 -0
- package/dist/git-cli/providers/pausedOperations.js +60 -40
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.js +11 -8
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/remotes.js +19 -10
- package/dist/git-cli/providers/remotes.js.map +1 -1
- package/dist/git-cli/providers/staging.js +40 -15
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/stash.d.ts +2 -0
- package/dist/git-cli/providers/stash.js +33 -18
- package/dist/git-cli/providers/stash.js.map +1 -1
- package/dist/git-cli/providers/status.d.ts +3 -1
- package/dist/git-cli/providers/status.js +38 -20
- package/dist/git-cli/providers/status.js.map +1 -1
- package/dist/git-cli/providers/tags.js +6 -4
- package/dist/git-cli/providers/tags.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +1 -0
- package/dist/git-cli/providers/worktrees.js +60 -31
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/git-cli/service.d.ts +6 -0
- package/dist/git-cli/service.js +5 -2
- package/dist/git-cli/service.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
- package/dist/plus/git-github/providers/github/status.d.ts +3 -1
- package/dist/plus/git-github/providers/github/status.js +1 -1
- package/dist/plus/git-github/providers/github/status.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +13 -2
- package/dist/plus/integrations/collectionMetadata.js +14 -2
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +2 -2
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +1 -0
- package/dist/plus/integrations/integrationService.js +1 -1
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +1 -0
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +41 -5
- package/dist/plus/integrations/models/gitHostIntegration.js +109 -30
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.js +1 -1
- package/dist/plus/integrations/models/issueReads.d.ts +17 -4
- package/dist/plus/integrations/providers/apiClients.d.ts +2 -0
- package/dist/plus/integrations/providers/apiClients.js +7 -1
- package/dist/plus/integrations/providers/apiClients.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +5 -4
- package/dist/plus/integrations/providers/azure/azure.js +38 -77
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.utils.js +20 -17
- package/dist/plus/integrations/providers/azure/azure.utils.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +27 -10
- package/dist/plus/integrations/providers/azure/models.js +40 -20
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +23 -0
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js +84 -0
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts +44 -0
- package/dist/plus/integrations/providers/azureDevOps.js +113 -22
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +45 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +121 -6
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +0 -1
- package/dist/plus/integrations/providers/jira-server.js +29 -19
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +5 -2
- package/dist/plus/integrations/providers/jira.js +63 -44
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +3 -4
- package/dist/plus/integrations/providers/jiraIssueByKey.js +3 -4
- package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +5 -5
- package/dist/plus/integrations/providers/linearIssuesEtag.js +6 -6
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +12 -3
- package/dist/plus/integrations/providers/models.js +16 -9
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +21 -33
- package/dist/plus/integrations/providers/providersApi.js +159 -49
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.d.ts +49 -15
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.js +132 -10
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js +8 -2
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/reads/cursors.js +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +0 -1
- package/dist/plus/integrations/reads/filters.d.ts +3 -3
- package/dist/plus/integrations/reads/filters.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +2 -2
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.utils.d.ts +13 -0
- package/dist/plus/integrations/reads/hierarchy.utils.js +26 -1
- package/dist/plus/integrations/reads/hierarchy.utils.js.map +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +2 -1
- package/dist/plus/integrations/reads/issueBatch.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +27 -18
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +2 -1
- package/dist/plus/integrations/reads/issues.js +19 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.js +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +12 -3
- package/dist/plus/integrations/reads/resolveRepository.js.map +1 -1
- package/dist/plus/integrations/reads/warnings.d.ts +11 -4
- package/dist/plus/integrations/reads/warnings.js +15 -5
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +48 -4
- package/dist/plus/integrations/results.js +33 -13
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/plus/integrations/utils/integration.utils.d.ts +6 -1
- package/dist/plus/integrations/utils/integration.utils.js +8 -1
- package/dist/plus/integrations/utils/integration.utils.js.map +1 -1
- package/dist/utils/env/node/exec.js +2 -2
- package/dist/utils/promiseCache.d.ts +10 -0
- package/dist/utils/promiseCache.js +17 -2
- package/dist/utils/promiseCache.js.map +1 -1
- package/docs/integrations.md +93 -31
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"status.js","names":[],"sources":["../../../../git-cli/src/providers/status.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitFile } from '@gitlens/git/models/file.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitConflictFile } from '@gitlens/git/models/staging.js';\nimport { GitStatus } from '@gitlens/git/models/status.js';\nimport type { GitStatusFile } from '@gitlens/git/models/statusFile.js';\nimport type { GitStatusSubProvider, GitWorkingChangesState } from '@gitlens/git/providers/status.js';\nimport type { GitCommandPriority, GitErrorHandling } from '@gitlens/git/run.types.js';\nimport { raceWithTimeout } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { createDisposable } from '@gitlens/utils/disposable.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { normalizePath, splitPath, stripFolderGlob } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport { PromiseMap } from '@gitlens/utils/promiseCache.js';\nimport { iterateByDelimiter } from '@gitlens/utils/string.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { GitResult } from '../exec/exec.types.js';\nimport type { Git } from '../exec/git.js';\nimport { defaultExceptionHandler, gitConfigsStatus, GitErrors } from '../exec/git.js';\nimport { parseGitConflictFiles } from '../parsers/indexParser.js';\nimport { parseGitStatus } from '../parsers/statusParser.js';\n\n/** Backstop when `advanced.git.timeout` is disabled (0). Independent of the command timeout so disabling it can't\n * also disable deadlock recovery — mirrors `@gate`'s always-on 5-min force-clear. */\nconst disabledTimeoutBackstopMs = 1000 * 60 * 5;\n\n/**\n * Deadlock-backstop duration for a status read (see `dedupeByStatusGeneration`), exported for testing.\n * Always returns a value so a wedged read recovers even with `advanced.git.timeout` disabled (which bounds git\n * *commands*, not deadlock recovery). With a timeout set, `gitTimeout * 2` sits above the per-command timeout so\n * `git.run` reads reject at their own timeout first; the backstop's real job is bounding the timeout-less\n * `git.stream` reads (`hasUntrackedFiles`/`hasConflictingFiles`).\n */\nexport function computeDeadlockBackstopMs(gitTimeout: number | undefined): number {\n\tconst timeout = gitTimeout ?? 60000;\n\treturn timeout > 0 ? timeout * 2 : disabledTimeoutBackstopMs;\n}\n\n/**\n * A non-default `untracked`/`branch` gets its own key, so a full-status caller never joins a narrower run; the\n * default stays `'getStatus'`, which `getStatusForPathCore`'s rename path joins.\n */\nfunction getStatusReadKey(options?: { untracked?: 'no' | 'normal' | 'all'; branch?: false }): string {\n\tif (options?.untracked == null && options?.branch !== false) return 'getStatus';\n\n\tconst parts: string[] = [];\n\tif (options?.untracked != null) {\n\t\tparts.push(`untracked=${options.untracked}`);\n\t}\n\tif (options?.branch === false) {\n\t\tparts.push('branch=false');\n\t}\n\treturn `getStatus:${parts.join(':')}`;\n}\n\nexport class StatusGitSubProvider implements GitStatusSubProvider {\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/** In-flight reads, keyed by `<read>\\0<repoPath>\\0<generation>`. `PromiseMap` (not a bare Map) so joiners\n\t * get per-caller cancellation: the shared run aborts only when ALL current callers do. */\n\tprivate readonly _pendingReads = new PromiseMap<string, unknown>();\n\n\t/**\n\t * Single-flight for point-in-time reads of mutable working-tree state — replaces `@gate`, which dedups on\n\t * repoPath with no notion of *when* a run started and so joins a pre-change read to a post-change caller\n\t * (see {@link Cache.getStatusGeneration}). Same-generation callers share one run (via a `PromiseMap`, so a\n\t * joiner cancelling can't reject the others); a caller in a newer generation gets a different key and a\n\t * fresh run; a `force` read advances the clock first, so it fences every later reader too, not just itself.\n\t * The exec-layer command dedup (`Git.pendingCommands`) is fenced automatically: each run carries this entry's\n\t * aggregate signal, whose id is part of the exec cache key, so a newer-generation run never joins an older\n\t * one's process; the generation-derived `correlationKey` is a readable second guard on that key. A `raceWithTimeout` backstop (scaled to `advanced.git.timeout`, see\n\t * {@link computeDeadlockBackstopMs}) replaces `@gate`'s 5-min force-clear so a never-settling read (a hung\n\t * `git.stream`, which has no per-command timeout) can't wedge same-generation callers — including blocking\n\t * awaiters like the commit flow — indefinitely.\n\t */\n\tprivate dedupeByStatusGeneration<T>(\n\t\trepoPath: string,\n\t\tread: string,\n\t\trun: (correlationKey: string, signal: AbortSignal | undefined) => Promise<T>,\n\t\tcancellation?: AbortSignal,\n\t\tforce?: boolean,\n\t): Promise<T> {\n\t\t// A `force` (user refresh) read is the user asserting the working tree may have changed without the watcher\n\t\t// observing it — the same class of event as a watcher tick, so it ADVANCES the clock rather than carving out\n\t\t// a private key for itself. A one-shot nonce would fence only this caller: the pre-assertion run stays\n\t\t// joinable, so the very next ordinary reader still picks up pre-change content — and, stamped with a newer\n\t\t// `Wip.revision` (assigned at producer start, not read start), applies it right back over the refreshed\n\t\t// result. Advancing is also CHEAPER than a nonce: concurrent readers join the one fresh read instead of each\n\t\t// spawning a private one.\n\t\tif (force) {\n\t\t\tthis.cache.incrementStatusGeneration(repoPath);\n\t\t}\n\t\tconst generation = this.cache.getStatusGeneration(repoPath);\n\t\t// `\\0` separators: `read`/`repoPath` are free-form (paths can contain `:`), so a printable delimiter could\n\t\t// collide (`getStatusForPath:/a:x` vs `getStatusForPath:/a` + `:x`).\n\t\tconst key = `${read}\\0${repoPath}\\0${generation}`;\n\t\tconst correlationKey = `status:${generation}`;\n\t\tconst backstopMs = computeDeadlockBackstopMs(this.git.options.gitTimeout);\n\n\t\treturn this._pendingReads.getOrCreate(\n\t\t\tkey,\n\t\t\t(cacheable, signal) => {\n\t\t\t\t// Point-in-time read: never memoize a settled value. `invalidate()` at the start makes the entry\n\t\t\t\t// self-evict on settle, so a later caller in this same generation re-reads (a newer generation\n\t\t\t\t// already gets a different key). `signal` is the aggregate — the run aborts only if every caller\n\t\t\t\t// cancels, so one caller's abort can't reject the others. The backstop rejects a wedged read so\n\t\t\t\t// waiters unblock and the entry self-evicts; it ALSO aborts the underlying git op (via `backstop`\n\t\t\t\t// linked into the run's signal) so a wedged read releases its GitQueue slot/process rather than\n\t\t\t\t// running orphaned — best-effort, since a truly-stuck process may ignore the abort.\n\t\t\t\tcacheable.invalidate();\n\t\t\t\tconst backstop = new AbortController();\n\t\t\t\tconst runSignal = signal != null ? AbortSignal.any([signal, backstop.signal]) : backstop.signal;\n\t\t\t\treturn raceWithTimeout(run(correlationKey, runSignal), backstopMs, backstop);\n\t\t\t},\n\t\t\tcancellation,\n\t\t) as Promise<T>;\n\t}\n\n\t@debug()\n\tgetStatus(\n\t\trepoPath: string | undefined,\n\t\toptions?: {\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tforce?: boolean;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tif (repoPath == null) return Promise.resolve(undefined);\n\n\t\t// `-u` already means `-uall`, so an explicit `'all'` shares the default run\n\t\tconst opts = options?.untracked === 'all' ? { ...options, untracked: undefined } : options;\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\tgetStatusReadKey(opts),\n\t\t\t(correlationKey, signal) =>\n\t\t\t\tthis.getStatusCore(repoPath, { ...opts, correlationKey: correlationKey }, signal),\n\t\t\tcancellation,\n\t\t\topts?.force,\n\t\t);\n\t}\n\n\tprivate async getStatusCore(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tcorrelationKey?: string;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tconst porcelainVersion = (await this.git.supports('git:status:porcelain-v2')) ? 2 : 1;\n\n\t\tconst result = await this.statusCore(\n\t\t\trepoPath,\n\t\t\tporcelainVersion,\n\t\t\t{\n\t\t\t\tsimilarityThreshold: this.context.config?.commits.similarityThreshold,\n\t\t\t\tpriority: options?.priority,\n\t\t\t\tcorrelationKey: options?.correlationKey,\n\t\t\t\tuntracked: options?.untracked,\n\t\t\t\tbranch: options?.branch,\n\t\t\t\terrors: 'throw',\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t\tconst status = parseGitStatus(result.stdout, repoPath, porcelainVersion);\n\n\t\tif (options?.branch === false) {\n\t\t\t// Without `--branch` a clean tree prints nothing at all, which the parser reads as no status\n\t\t\tif (status == null && result.completion.status === 'exited' && result.exitCode === 0) {\n\t\t\t\treturn new GitStatus(normalizePath(repoPath), '', '', []);\n\t\t\t}\n\t\t\t// No branch name either, which `GitStatus` reads as detached, so there is no paused rebase to look up\n\t\t\treturn status;\n\t\t}\n\n\t\tif (status?.detached) {\n\t\t\tconst pausedOpStatus = await this.provider.pausedOps?.getPausedOperationStatus?.(\n\t\t\t\trepoPath,\n\t\t\t\tundefined,\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\tif (pausedOpStatus?.type === 'rebase') {\n\t\t\t\treturn new GitStatus(\n\t\t\t\t\trepoPath,\n\t\t\t\t\tpausedOpStatus.incoming.name,\n\t\t\t\t\tstatus.sha,\n\t\t\t\t\tstatus.files,\n\t\t\t\t\tstatus.upstream,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn status;\n\t}\n\n\t@debug()\n\tasync getStatusForFile(\n\t\trepoPath: string,\n\t\tpathOrUri: string | Uri,\n\t\toptions?: { renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile | undefined> {\n\t\tconst files = await this.getStatusForPathCore(\n\t\t\trepoPath,\n\t\t\ttoFsPath(pathOrUri),\n\t\t\t{ ...options, exact: true },\n\t\t\tcancellation,\n\t\t);\n\t\treturn files?.[0];\n\t}\n\n\t@debug()\n\tasync getStatusForPath(\n\t\trepoPath: string,\n\t\tpathOrUri: string | Uri,\n\t\toptions?: { renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\treturn this.getStatusForPathCore(repoPath, toFsPath(pathOrUri), { ...options, exact: false }, cancellation);\n\t}\n\n\tprivate async getStatusForPathCore(\n\t\trepoPath: string,\n\t\tpathOrUri: string,\n\t\toptions: { exact: boolean; renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\tconst relativePath = stripFolderGlob(splitPath(pathOrUri, repoPath)[0]);\n\n\t\t// Rename-aware queries can't scope by pathspec (that disables Git's rename detection), so they run the\n\t\t// SAME full `git status` as `getStatus`. Delegate to it — sharing one process/dedup entry — and filter,\n\t\t// rather than spawning a second identical `git status`.\n\t\tif (options.renames !== false) {\n\t\t\t// The rename path keeps the default handling the scoped read gets\n\t\t\tconst status = await this.getStatus(repoPath, undefined, cancellation).catch((ex: unknown) => {\n\t\t\t\tdefaultExceptionHandler(ex as Error, repoPath);\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\tif (status == null) return undefined;\n\n\t\t\tif (options.exact) {\n\t\t\t\tconst file = status.files.find(f => f.path === relativePath);\n\t\t\t\treturn file ? [file] : undefined;\n\t\t\t}\n\t\t\treturn status.files.filter(f => f.path.startsWith(relativePath));\n\t\t}\n\n\t\t// Non-rename query: pathspec-scoped `git status` (a distinct command), deduped on its own key. `exact`\n\t\t// is NOT in the key — the pathspec-scoped command is identical for exact/non-exact, so both share one run.\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t// Free-form `relativePath` (may contain `:`) goes LAST so the prefix can't be shifted into it.\n\t\t\t`getStatusForPath:${relativePath}`,\n\t\t\t(correlationKey, signal) => this.getStatusForPathScoped(repoPath, relativePath, correlationKey, signal),\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async getStatusForPathScoped(\n\t\trepoPath: string,\n\t\trelativePath: string,\n\t\tcorrelationKey: string,\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\tconst porcelainVersion = (await this.git.supports('git:status:porcelain-v2')) ? 2 : 1;\n\t\tconst result = await this.statusCore(\n\t\t\trepoPath,\n\t\t\tporcelainVersion,\n\t\t\t{ similarityThreshold: this.context.config?.commits.similarityThreshold, correlationKey: correlationKey },\n\t\t\tcancellation,\n\t\t\trelativePath,\n\t\t);\n\n\t\tconst status = parseGitStatus(result.stdout, repoPath, porcelainVersion);\n\t\treturn status?.files;\n\t}\n\n\tprivate async statusCore(\n\t\trepoPath: string,\n\t\tporcelainVersion: number = 1,\n\t\toptions?: {\n\t\t\tsimilarityThreshold?: number | null;\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tcorrelationKey?: string;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t\terrors?: GitErrorHandling;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t\t...pathspecs: string[]\n\t): Promise<GitResult> {\n\t\tconst params = ['status', porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain'];\n\t\tif (options?.branch !== false) {\n\t\t\tparams.push('--branch');\n\t\t}\n\t\tparams.push(options?.untracked != null ? `-u${options.untracked}` : '-u');\n\t\tif (await this.git.supports('git:status:find-renames')) {\n\t\t\tparams.push(\n\t\t\t\t`--find-renames${options?.similarityThreshold == null ? '' : `=${options.similarityThreshold}%`}`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.git.run(\n\t\t\t{\n\t\t\t\tcwd: repoPath,\n\t\t\t\tcancellation: cancellation,\n\t\t\t\tconfigs: gitConfigsStatus,\n\t\t\t\tenv: { GIT_OPTIONAL_LOCKS: '0' },\n\t\t\t\tcorrelationKey: options?.correlationKey,\n\t\t\t\t...(options?.errors != null ? { errors: options.errors } : undefined),\n\t\t\t\t...(options?.priority != null ? { priority: options.priority } : undefined),\n\t\t\t},\n\t\t\t...params,\n\t\t\t'--',\n\t\t\t...pathspecs,\n\t\t);\n\t}\n\n\t@debug()\n\thasWorkingChanges(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tstaged?: boolean;\n\t\t\tunstaged?: boolean;\n\t\t\tuntracked?: boolean;\n\t\t\tpriority?: GitCommandPriority;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<boolean> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst staged = options?.staged ?? true;\n\t\tconst unstaged = options?.unstaged ?? true;\n\t\tconst untracked = options?.untracked ?? true;\n\t\t// `priority` is in the key even though it doesn't change the answer: a joiner INHERITS the in-flight run's\n\t\t// scheduling. `GitQueue` refuses to start background work while anything is waiting at normal/interactive,\n\t\t// so letting a foreground caller (the overview's dirty pill, the Worktrees view) join a `background` probe\n\t\t// would strand it for the whole graph load. Splitting the two lanes costs at most one extra spawn; joining\n\t\t// costs unbounded foreground latency.\n\t\tconst priority = options?.priority ?? 'default';\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t`hasWorkingChanges:${staged}:${unstaged}:${untracked}:${priority}`,\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tif (staged || unstaged) {\n\t\t\t\t\tconst diffQuiet = (revision: string | undefined) =>\n\t\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t\t\t...(options?.priority != null ? { priority: options.priority } : undefined),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t\t\trevision,\n\t\t\t\t\t\t\t'--',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tlet result;\n\t\t\t\t\tif (staged && unstaged) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresult = await diffQuiet('HEAD');\n\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t// Before the first commit HEAD names nothing; everything staged or modified is a change\n\t\t\t\t\t\t\t// against the empty tree. `diff HEAD --` names only HEAD, so its \"bad revision\" is that case\n\t\t\t\t\t\t\t// without re-validating HEAD (a corrupt HEAD then reads as dirty, the safe answer)\n\t\t\t\t\t\t\tif (GitErrors.badRevision.exec(String(ex))?.[1]?.toUpperCase() !== 'HEAD') throw ex;\n\n\t\t\t\t\t\t\tresult = await diffQuiet(await this.provider.revision.getEmptyTreeSha(repoPath));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = await diffQuiet(staged ? '--staged' : undefined);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result.exitCode === 1) {\n\t\t\t\t\t\tif (staged && unstaged) {\n\t\t\t\t\t\t\tscope?.addExitInfo('has staged and unstaged changes');\n\t\t\t\t\t\t} else if (staged) {\n\t\t\t\t\t\t\tscope?.addExitInfo('has staged changes');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tscope?.addExitInfo('has unstaged changes');\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check for untracked files. NOTE: this runs through `git.stream`, which spawns directly\n\t\t\t\t// and never enters the queue — so `priority` above doesn't reach it. Only clean worktrees\n\t\t\t\t// get this far (a dirty one already returned above), and callers fanning out across many\n\t\t\t\t// worktrees are expected to bound their own concurrency.\n\t\t\t\tif (untracked) {\n\t\t\t\t\tconst hasUntracked = await this.hasUntrackedFiles(repoPath, signal);\n\t\t\t\t\tif (hasUntracked) {\n\t\t\t\t\t\tscope?.addExitInfo('has untracked files');\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tscope?.addExitInfo('no working changes');\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t@debug()\n\tgetWorkingChangesState(repoPath: string, cancellation?: AbortSignal): Promise<GitWorkingChangesState> {\n\t\tconst scope = getScopedLogger();\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'getWorkingChangesState',\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst [stagedResult, unstagedResult, untrackedResult] = await Promise.allSettled([\n\t\t\t\t\t// Check for staged changes\n\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t\t'--staged',\n\t\t\t\t\t),\n\t\t\t\t\t// Check for unstaged changes\n\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t),\n\t\t\t\t\t// Check for untracked files\n\t\t\t\t\tthis.hasUntrackedFiles(repoPath, signal),\n\t\t\t\t]);\n\n\t\t\t\tfor (const settled of [stagedResult, unstagedResult, untrackedResult]) {\n\t\t\t\t\tif (settled.status === 'rejected') throw settled.reason;\n\t\t\t\t}\n\n\t\t\t\tconst result = {\n\t\t\t\t\tstaged: getSettledValue(stagedResult)?.exitCode === 1,\n\t\t\t\t\tunstaged: getSettledValue(unstagedResult)?.exitCode === 1,\n\t\t\t\t\tuntracked: getSettledValue(untrackedResult) === true,\n\t\t\t\t};\n\n\t\t\t\tscope?.addExitInfo(\n\t\t\t\t\tresult.staged || result.unstaged || result.untracked\n\t\t\t\t\t\t? `has ${result.staged ? 'staged' : ''}${result.unstaged ? (result.staged ? ', unstaged' : 'unstaged ') : ''}${\n\t\t\t\t\t\t\t\tresult.untracked ? (result.staged || result.unstaged ? ', untracked' : 'untracked') : ''\n\t\t\t\t\t\t\t} changes`\n\t\t\t\t\t\t: 'no working changes',\n\t\t\t\t);\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\thasConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean> {\n\t\t// Route through `dedupeByStatusGeneration` (like every other point-in-time read here) for the join-fence\n\t\t// and the `raceWithTimeout` backstop — a bare `git.stream` has no per-command timeout and could wedge.\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'hasConflictingFiles',\n\t\t\tasync (_correlationKey, signal) => {\n\t\t\t\tconst stream = this.git.stream({ cwd: repoPath, cancellation: signal }, 'ls-files', '--unmerged');\n\t\t\t\tusing _streamDisposer = createDisposable(() => void stream.return?.(undefined));\n\n\t\t\t\t// Early exit on first chunk - breaking causes SIGPIPE, killing git process\n\t\t\t\tfor await (const _chunk of stream) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t@debug()\n\tgetConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitConflictFile[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'getConflictingFiles',\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t{ cwd: repoPath, cancellation: signal, errors: 'throw', correlationKey: correlationKey },\n\t\t\t\t\t'ls-files',\n\t\t\t\t\t'-z',\n\t\t\t\t\t'--unmerged',\n\t\t\t\t);\n\n\t\t\t\tif (!result.stdout) {\n\t\t\t\t\tscope?.addExitInfo('no conflicting files');\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst files = parseGitConflictFiles(result.stdout, repoPath);\n\t\t\t\tscope?.addExitInfo(`${String(files.length)} conflicting file(s)`);\n\t\t\t\treturn files;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async hasUntrackedFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean> {\n\t\tconst stream = this.git.stream(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'ls-files',\n\t\t\t// '-z', // Unneeded since we are only looking for presence\n\t\t\t'--others',\n\t\t\t'--exclude-standard',\n\t\t);\n\t\tusing _streamDisposer = createDisposable(() => void stream.return?.(undefined));\n\n\t\t// Early exit on first chunk - breaking causes SIGPIPE, killing git process\n\t\tfor await (const _chunk of stream) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@debug()\n\tgetUntrackedFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitFile[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'getUntrackedFiles',\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t{ cwd: repoPath, cancellation: signal, errors: 'throw', correlationKey: correlationKey },\n\t\t\t\t\t'ls-files',\n\t\t\t\t\t'-z',\n\t\t\t\t\t'--others',\n\t\t\t\t\t'--exclude-standard',\n\t\t\t\t);\n\n\t\t\t\tif (!result.stdout) {\n\t\t\t\t\tscope?.addExitInfo('no untracked files');\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst files: GitFile[] = [];\n\n\t\t\t\tfor (const line of iterateByDelimiter(result.stdout, '\\0')) {\n\t\t\t\t\tif (!line.length) continue;\n\n\t\t\t\t\tfiles.push({ path: line, repoPath: repoPath, status: GitFileWorkingTreeStatus.Untracked });\n\t\t\t\t}\n\n\t\t\t\tscope?.addExitInfo(`${String(files.length)} untracked file(s)`);\n\t\t\t\treturn files;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"status.js","names":[],"sources":["../../../../git-cli/src/providers/status.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitFile } from '@gitlens/git/models/file.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitConflictFile } from '@gitlens/git/models/staging.js';\nimport { GitStatus } from '@gitlens/git/models/status.js';\nimport type { GitStatusFile } from '@gitlens/git/models/statusFile.js';\nimport type { GitStatusSubProvider, GitWorkingChangesState } from '@gitlens/git/providers/status.js';\nimport type { GitCommandPriority, GitErrorHandling } from '@gitlens/git/run.types.js';\nimport { raceWithTimeout } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { createDisposable } from '@gitlens/utils/disposable.js';\nimport { chunkByStringLength } from '@gitlens/utils/iterable.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { normalizePath, splitPath, stripFolderGlob } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport { PromiseMap } from '@gitlens/utils/promiseCache.js';\nimport { iterateByDelimiter } from '@gitlens/utils/string.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { GitResult } from '../exec/exec.types.js';\nimport type { Git } from '../exec/git.js';\nimport { defaultExceptionHandler, gitConfigsStatus, GitErrors, maxGitCliLength } from '../exec/git.js';\nimport { parseGitConflictFiles } from '../parsers/indexParser.js';\nimport { parseGitStatus } from '../parsers/statusParser.js';\n\n/** Backstop when `advanced.git.timeout` is disabled (0). Independent of the command timeout so disabling it can't\n * also disable deadlock recovery — mirrors `@gate`'s always-on 5-min force-clear. */\nconst disabledTimeoutBackstopMs = 1000 * 60 * 5;\n\n/**\n * Deadlock-backstop duration for a status read (see `dedupeByStatusGeneration`), exported for testing.\n * Always returns a value so a wedged read recovers even with `advanced.git.timeout` disabled (which bounds git\n * *commands*, not deadlock recovery). With a timeout set, `gitTimeout * 2` sits above the per-command timeout so\n * `git.run` reads reject at their own timeout first; the backstop's real job is bounding the timeout-less\n * `git.stream` reads (`hasUntrackedFiles`/`hasConflictingFiles`).\n */\nexport function computeDeadlockBackstopMs(gitTimeout: number | undefined): number {\n\tconst timeout = gitTimeout ?? 60000;\n\treturn timeout > 0 ? timeout * 2 : disabledTimeoutBackstopMs;\n}\n\n/**\n * A non-default `untracked`/`branch` gets its own key, so a full-status caller never joins a narrower run; the\n * default stays `'getStatus'`, which `getStatusForPathCore`'s rename path joins.\n */\nfunction getStatusReadKey(options?: { untracked?: 'no' | 'normal' | 'all'; branch?: false }): string {\n\tif (options?.untracked == null && options?.branch !== false) return 'getStatus';\n\n\tconst parts: string[] = [];\n\tif (options?.untracked != null) {\n\t\tparts.push(`untracked=${options.untracked}`);\n\t}\n\tif (options?.branch === false) {\n\t\tparts.push('branch=false');\n\t}\n\treturn `getStatus:${parts.join(':')}`;\n}\n\nexport class StatusGitSubProvider implements GitStatusSubProvider {\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/** In-flight reads, keyed by `<read>\\0<repoPath>\\0<generation>`. `PromiseMap` (not a bare Map) so joiners\n\t * get per-caller cancellation: the shared run aborts only when ALL current callers do. */\n\tprivate readonly _pendingReads = new PromiseMap<string, unknown>();\n\n\t/**\n\t * Single-flight for point-in-time reads of mutable working-tree state — replaces `@gate`, which dedups on\n\t * repoPath with no notion of *when* a run started and so joins a pre-change read to a post-change caller\n\t * (see {@link Cache.getStatusGeneration}). Same-generation callers share one run (via a `PromiseMap`, so a\n\t * joiner cancelling can't reject the others); a caller in a newer generation gets a different key and a\n\t * fresh run; a `force` read advances the clock first, so it fences every later reader too, not just itself.\n\t * The exec-layer command dedup (`Git.pendingCommands`) is fenced automatically: each run carries this entry's\n\t * aggregate signal, whose id is part of the exec cache key, so a newer-generation run never joins an older\n\t * one's process; the generation-derived `correlationKey` is a readable second guard on that key. A `raceWithTimeout` backstop (scaled to `advanced.git.timeout`, see\n\t * {@link computeDeadlockBackstopMs}) replaces `@gate`'s 5-min force-clear so a never-settling read (a hung\n\t * `git.stream`, which has no per-command timeout) can't wedge same-generation callers — including blocking\n\t * awaiters like the commit flow — indefinitely.\n\t */\n\tprivate dedupeByStatusGeneration<T>(\n\t\trepoPath: string,\n\t\tread: string,\n\t\trun: (correlationKey: string, signal: AbortSignal | undefined) => Promise<T>,\n\t\tcancellation?: AbortSignal,\n\t\tforce?: boolean,\n\t): Promise<T> {\n\t\t// A `force` (user refresh) read is the user asserting the working tree may have changed without the watcher\n\t\t// observing it — the same class of event as a watcher tick, so it ADVANCES the clock rather than carving out\n\t\t// a private key for itself. A one-shot nonce would fence only this caller: the pre-assertion run stays\n\t\t// joinable, so the very next ordinary reader still picks up pre-change content — and, stamped with a newer\n\t\t// `Wip.revision` (assigned at producer start, not read start), applies it right back over the refreshed\n\t\t// result. Advancing is also CHEAPER than a nonce: concurrent readers join the one fresh read instead of each\n\t\t// spawning a private one.\n\t\tif (force) {\n\t\t\tthis.cache.incrementStatusGeneration(repoPath);\n\t\t}\n\t\tconst generation = this.cache.getStatusGeneration(repoPath);\n\t\t// `\\0` separators: `read`/`repoPath` are free-form (paths can contain `:`), so a printable delimiter could\n\t\t// collide (`getStatusForPath:/a:x` vs `getStatusForPath:/a` + `:x`).\n\t\tconst key = `${read}\\0${repoPath}\\0${generation}`;\n\t\tconst correlationKey = `status:${generation}`;\n\t\tconst backstopMs = computeDeadlockBackstopMs(this.git.options.gitTimeout);\n\n\t\treturn this._pendingReads.getOrCreate(\n\t\t\tkey,\n\t\t\t(cacheable, signal) => {\n\t\t\t\t// Point-in-time read: never memoize a settled value. `invalidate()` at the start makes the entry\n\t\t\t\t// self-evict on settle, so a later caller in this same generation re-reads (a newer generation\n\t\t\t\t// already gets a different key). `signal` is the aggregate — the run aborts only if every caller\n\t\t\t\t// cancels, so one caller's abort can't reject the others. The backstop rejects a wedged read so\n\t\t\t\t// waiters unblock and the entry self-evicts; it ALSO aborts the underlying git op (via `backstop`\n\t\t\t\t// linked into the run's signal) so a wedged read releases its GitQueue slot/process rather than\n\t\t\t\t// running orphaned — best-effort, since a truly-stuck process may ignore the abort.\n\t\t\t\tcacheable.invalidate();\n\t\t\t\tconst backstop = new AbortController();\n\t\t\t\tconst runSignal = signal != null ? AbortSignal.any([signal, backstop.signal]) : backstop.signal;\n\t\t\t\treturn raceWithTimeout(run(correlationKey, runSignal), backstopMs, backstop);\n\t\t\t},\n\t\t\tcancellation,\n\t\t) as Promise<T>;\n\t}\n\n\t@debug()\n\tgetStatus(\n\t\trepoPath: string | undefined,\n\t\toptions?: {\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tforce?: boolean;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tif (repoPath == null) return Promise.resolve(undefined);\n\n\t\t// `-u` already means `-uall`, so an explicit `'all'` shares the default run\n\t\tconst opts = options?.untracked === 'all' ? { ...options, untracked: undefined } : options;\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\tgetStatusReadKey(opts),\n\t\t\t(correlationKey, signal) =>\n\t\t\t\tthis.getStatusCore(repoPath, { ...opts, correlationKey: correlationKey }, signal),\n\t\t\tcancellation,\n\t\t\topts?.force,\n\t\t);\n\t}\n\n\tprivate async getStatusCore(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tcorrelationKey?: string;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatus | undefined> {\n\t\tconst porcelainVersion = (await this.git.supports('git:status:porcelain-v2')) ? 2 : 1;\n\n\t\tconst result = await this.statusCore(\n\t\t\trepoPath,\n\t\t\tporcelainVersion,\n\t\t\t{\n\t\t\t\tsimilarityThreshold: this.context.config?.commits.similarityThreshold,\n\t\t\t\tpriority: options?.priority,\n\t\t\t\tcorrelationKey: options?.correlationKey,\n\t\t\t\tuntracked: options?.untracked,\n\t\t\t\tbranch: options?.branch,\n\t\t\t\terrors: 'throw',\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t\tconst status = parseGitStatus(result.stdout, repoPath, porcelainVersion);\n\n\t\tif (options?.branch === false) {\n\t\t\t// Without `--branch` a clean tree prints nothing at all, which the parser reads as no status\n\t\t\tif (status == null && result.completion.status === 'exited' && result.exitCode === 0) {\n\t\t\t\treturn new GitStatus(normalizePath(repoPath), '', '', []);\n\t\t\t}\n\t\t\t// No branch name either, which `GitStatus` reads as detached, so there is no paused rebase to look up\n\t\t\treturn status;\n\t\t}\n\n\t\tif (status?.detached) {\n\t\t\tconst pausedOpStatus = await this.provider.pausedOps?.getPausedOperationStatus?.(\n\t\t\t\trepoPath,\n\t\t\t\tundefined,\n\t\t\t\tcancellation,\n\t\t\t);\n\t\t\tif (pausedOpStatus?.type === 'rebase') {\n\t\t\t\treturn new GitStatus(\n\t\t\t\t\trepoPath,\n\t\t\t\t\tpausedOpStatus.incoming.name,\n\t\t\t\t\tstatus.sha,\n\t\t\t\t\tstatus.files,\n\t\t\t\t\tstatus.upstream,\n\t\t\t\t\ttrue,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn status;\n\t}\n\n\t@debug()\n\tasync getStatusForFile(\n\t\trepoPath: string,\n\t\tpathOrUri: string | Uri,\n\t\toptions?: { renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile | undefined> {\n\t\tconst files = await this.getStatusForPathCore(\n\t\t\trepoPath,\n\t\t\ttoFsPath(pathOrUri),\n\t\t\t{ ...options, exact: true },\n\t\t\tcancellation,\n\t\t);\n\t\treturn files?.[0];\n\t}\n\n\t@debug()\n\tasync getStatusForPath(\n\t\trepoPath: string,\n\t\tpathOrUri: string | Uri,\n\t\toptions?: { renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\treturn this.getStatusForPathCore(repoPath, toFsPath(pathOrUri), { ...options, exact: false }, cancellation);\n\t}\n\n\tprivate async getStatusForPathCore(\n\t\trepoPath: string,\n\t\tpathOrUri: string,\n\t\toptions: { exact: boolean; renames?: boolean },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\tconst relativePath = stripFolderGlob(splitPath(pathOrUri, repoPath)[0]);\n\n\t\t// Rename-aware queries can't scope by pathspec (that disables Git's rename detection), so they run the\n\t\t// SAME full `git status` as `getStatus`. Delegate to it — sharing one process/dedup entry — and filter,\n\t\t// rather than spawning a second identical `git status`.\n\t\tif (options.renames !== false) {\n\t\t\t// The rename path keeps the default handling the scoped read gets\n\t\t\tconst status = await this.getStatus(repoPath, undefined, cancellation).catch((ex: unknown) => {\n\t\t\t\tdefaultExceptionHandler(ex as Error, repoPath);\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t\tif (status == null) return undefined;\n\n\t\t\tif (options.exact) {\n\t\t\t\tconst file = status.files.find(f => f.path === relativePath);\n\t\t\t\treturn file ? [file] : undefined;\n\t\t\t}\n\t\t\treturn status.files.filter(f => f.path.startsWith(relativePath));\n\t\t}\n\n\t\t// Non-rename query: pathspec-scoped `git status` (a distinct command), deduped on its own key. `exact`\n\t\t// is NOT in the key — the pathspec-scoped command is identical for exact/non-exact, so both share one run.\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t// Free-form `relativePath` (may contain `:`) goes LAST so the prefix can't be shifted into it.\n\t\t\t`getStatusForPath:${relativePath}`,\n\t\t\t(correlationKey, signal) => this.getStatusForPathScoped(repoPath, relativePath, correlationKey, signal),\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async getStatusForPathScoped(\n\t\trepoPath: string,\n\t\trelativePath: string,\n\t\tcorrelationKey: string,\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStatusFile[] | undefined> {\n\t\tconst porcelainVersion = (await this.git.supports('git:status:porcelain-v2')) ? 2 : 1;\n\t\tconst result = await this.statusCore(\n\t\t\trepoPath,\n\t\t\tporcelainVersion,\n\t\t\t{ similarityThreshold: this.context.config?.commits.similarityThreshold, correlationKey: correlationKey },\n\t\t\tcancellation,\n\t\t\trelativePath,\n\t\t);\n\n\t\tconst status = parseGitStatus(result.stdout, repoPath, porcelainVersion);\n\t\treturn status?.files;\n\t}\n\n\tprivate async statusCore(\n\t\trepoPath: string,\n\t\tporcelainVersion: number = 1,\n\t\toptions?: {\n\t\t\tsimilarityThreshold?: number | null;\n\t\t\tpriority?: GitCommandPriority;\n\t\t\tcorrelationKey?: string;\n\t\t\tuntracked?: 'no' | 'normal' | 'all';\n\t\t\tbranch?: false;\n\t\t\terrors?: GitErrorHandling;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t\t...pathspecs: string[]\n\t): Promise<GitResult> {\n\t\tconst params = ['status', porcelainVersion >= 2 ? `--porcelain=v${porcelainVersion}` : '--porcelain'];\n\t\tif (options?.branch !== false) {\n\t\t\tparams.push('--branch');\n\t\t}\n\t\tparams.push(options?.untracked != null ? `-u${options.untracked}` : '-u');\n\t\tif (await this.git.supports('git:status:find-renames')) {\n\t\t\tparams.push(\n\t\t\t\t`--find-renames${options?.similarityThreshold == null ? '' : `=${options.similarityThreshold}%`}`,\n\t\t\t);\n\t\t}\n\n\t\treturn this.git.run(\n\t\t\t{\n\t\t\t\tcwd: repoPath,\n\t\t\t\tcancellation: cancellation,\n\t\t\t\tconfigs: gitConfigsStatus,\n\t\t\t\tenv: { GIT_OPTIONAL_LOCKS: '0' },\n\t\t\t\tcorrelationKey: options?.correlationKey,\n\t\t\t\t...(options?.errors != null ? { errors: options.errors } : undefined),\n\t\t\t\t...(options?.priority != null ? { priority: options.priority } : undefined),\n\t\t\t},\n\t\t\t...params,\n\t\t\t'--',\n\t\t\t...pathspecs,\n\t\t);\n\t}\n\n\t@debug()\n\thasWorkingChanges(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tstaged?: boolean;\n\t\t\tunstaged?: boolean;\n\t\t\tuntracked?: boolean;\n\t\t\tpriority?: GitCommandPriority;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<boolean> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst staged = options?.staged ?? true;\n\t\tconst unstaged = options?.unstaged ?? true;\n\t\tconst untracked = options?.untracked ?? true;\n\t\t// `priority` is in the key even though it doesn't change the answer: a joiner INHERITS the in-flight run's\n\t\t// scheduling. `GitQueue` refuses to start background work while anything is waiting at normal/interactive,\n\t\t// so letting a foreground caller (the overview's dirty pill, the Worktrees view) join a `background` probe\n\t\t// would strand it for the whole graph load. Splitting the two lanes costs at most one extra spawn; joining\n\t\t// costs unbounded foreground latency.\n\t\tconst priority = options?.priority ?? 'default';\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t`hasWorkingChanges:${staged}:${unstaged}:${untracked}:${priority}`,\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tif (staged || unstaged) {\n\t\t\t\t\tconst diffQuiet = (revision: string | undefined) =>\n\t\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t\t\t...(options?.priority != null ? { priority: options.priority } : undefined),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t\t\trevision,\n\t\t\t\t\t\t\t'--',\n\t\t\t\t\t\t);\n\n\t\t\t\t\tlet result;\n\t\t\t\t\tif (staged && unstaged) {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresult = await diffQuiet('HEAD');\n\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t// Before the first commit HEAD names nothing; everything staged or modified is a change\n\t\t\t\t\t\t\t// against the empty tree. `diff HEAD --` names only HEAD, so its \"bad revision\" is that case\n\t\t\t\t\t\t\t// without re-validating HEAD (a corrupt HEAD then reads as dirty, the safe answer)\n\t\t\t\t\t\t\tif (GitErrors.badRevision.exec(String(ex))?.[1]?.toUpperCase() !== 'HEAD') throw ex;\n\n\t\t\t\t\t\t\tresult = await diffQuiet(await this.provider.revision.getEmptyTreeSha(repoPath));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = await diffQuiet(staged ? '--staged' : undefined);\n\t\t\t\t\t}\n\n\t\t\t\t\tif (result.exitCode === 1) {\n\t\t\t\t\t\tif (staged && unstaged) {\n\t\t\t\t\t\t\tscope?.addExitInfo('has staged and unstaged changes');\n\t\t\t\t\t\t} else if (staged) {\n\t\t\t\t\t\t\tscope?.addExitInfo('has staged changes');\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tscope?.addExitInfo('has unstaged changes');\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Check for untracked files. NOTE: this runs through `git.stream`, which spawns directly\n\t\t\t\t// and never enters the queue — so `priority` above doesn't reach it. Only clean worktrees\n\t\t\t\t// get this far (a dirty one already returned above), and callers fanning out across many\n\t\t\t\t// worktrees are expected to bound their own concurrency.\n\t\t\t\tif (untracked) {\n\t\t\t\t\tconst hasUntracked = await this.hasUntrackedFiles(repoPath, signal);\n\t\t\t\t\tif (hasUntracked) {\n\t\t\t\t\t\tscope?.addExitInfo('has untracked files');\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tscope?.addExitInfo('no working changes');\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t@debug()\n\tgetWorkingChangesState(repoPath: string, cancellation?: AbortSignal): Promise<GitWorkingChangesState> {\n\t\tconst scope = getScopedLogger();\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'getWorkingChangesState',\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst [stagedResult, unstagedResult, untrackedResult] = await Promise.allSettled([\n\t\t\t\t\t// Check for staged changes\n\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t\t'--staged',\n\t\t\t\t\t),\n\t\t\t\t\t// Check for unstaged changes\n\t\t\t\t\tthis.git.run(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tcwd: repoPath,\n\t\t\t\t\t\t\tcancellation: signal,\n\t\t\t\t\t\t\terrors: 'throw',\n\t\t\t\t\t\t\texpectedExitCodes: [1],\n\t\t\t\t\t\t\tcorrelationKey: correlationKey,\n\t\t\t\t\t\t},\n\t\t\t\t\t\t'diff',\n\t\t\t\t\t\t'--quiet',\n\t\t\t\t\t),\n\t\t\t\t\t// Check for untracked files\n\t\t\t\t\tthis.hasUntrackedFiles(repoPath, signal),\n\t\t\t\t]);\n\n\t\t\t\tfor (const settled of [stagedResult, unstagedResult, untrackedResult]) {\n\t\t\t\t\tif (settled.status === 'rejected') throw settled.reason;\n\t\t\t\t}\n\n\t\t\t\tconst result = {\n\t\t\t\t\tstaged: getSettledValue(stagedResult)?.exitCode === 1,\n\t\t\t\t\tunstaged: getSettledValue(unstagedResult)?.exitCode === 1,\n\t\t\t\t\tuntracked: getSettledValue(untrackedResult) === true,\n\t\t\t\t};\n\n\t\t\t\tscope?.addExitInfo(\n\t\t\t\t\tresult.staged || result.unstaged || result.untracked\n\t\t\t\t\t\t? `has ${result.staged ? 'staged' : ''}${result.unstaged ? (result.staged ? ', unstaged' : 'unstaged ') : ''}${\n\t\t\t\t\t\t\t\tresult.untracked ? (result.staged || result.unstaged ? ', untracked' : 'untracked') : ''\n\t\t\t\t\t\t\t} changes`\n\t\t\t\t\t\t: 'no working changes',\n\t\t\t\t);\n\n\t\t\t\treturn result;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\thasConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean> {\n\t\t// Route through `dedupeByStatusGeneration` (like every other point-in-time read here) for the join-fence\n\t\t// and the `raceWithTimeout` backstop — a bare `git.stream` has no per-command timeout and could wedge.\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'hasConflictingFiles',\n\t\t\tasync (_correlationKey, signal) => {\n\t\t\t\tconst stream = this.git.stream({ cwd: repoPath, cancellation: signal }, 'ls-files', '--unmerged');\n\t\t\t\tusing _streamDisposer = createDisposable(() => void stream.return?.(undefined));\n\n\t\t\t\t// Early exit on first chunk - breaking causes SIGPIPE, killing git process\n\t\t\t\tfor await (const _chunk of stream) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t@debug()\n\tgetConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitConflictFile[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\t'getConflictingFiles',\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t{ cwd: repoPath, cancellation: signal, errors: 'throw', correlationKey: correlationKey },\n\t\t\t\t\t'ls-files',\n\t\t\t\t\t'-z',\n\t\t\t\t\t'--unmerged',\n\t\t\t\t);\n\n\t\t\t\tif (!result.stdout) {\n\t\t\t\t\tscope?.addExitInfo('no conflicting files');\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\n\t\t\t\tconst files = parseGitConflictFiles(result.stdout, repoPath);\n\t\t\t\tscope?.addExitInfo(`${String(files.length)} conflicting file(s)`);\n\t\t\t\treturn files;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\tprivate async hasUntrackedFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean> {\n\t\tconst stream = this.git.stream(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'ls-files',\n\t\t\t// '-z', // Unneeded since we are only looking for presence\n\t\t\t'--others',\n\t\t\t'--exclude-standard',\n\t\t);\n\t\tusing _streamDisposer = createDisposable(() => void stream.return?.(undefined));\n\n\t\t// Early exit on first chunk - breaking causes SIGPIPE, killing git process\n\t\tfor await (const _chunk of stream) {\n\t\t\treturn true;\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t@debug()\n\tgetUntrackedFiles(\n\t\trepoPath: string,\n\t\toptions?: { paths?: readonly string[] },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFile[]> {\n\t\tconst scope = getScopedLogger();\n\n\t\tconst paths = options?.paths;\n\t\t// No pathspec means \"everything\" to git, which is not what an empty list asks for\n\t\tif (paths != null && !paths.length) return Promise.resolve([]);\n\n\t\t// Literal pathspecs so a folder named like a glob (`[id]/`) doesn't match its siblings\n\t\tconst pathspecs = paths?.map(p => `:(literal)${p}`);\n\n\t\t// Path-scoped reads join only an identical path set; `\\0` can't appear in a path\n\t\tconst read = pathspecs != null ? `getUntrackedFiles\\0${pathspecs.join('\\0')}` : 'getUntrackedFiles';\n\n\t\treturn this.dedupeByStatusGeneration(\n\t\t\trepoPath,\n\t\t\tread,\n\t\t\tasync (correlationKey, signal) => {\n\t\t\t\tconst prefix = ['ls-files', '-z', '--others', '--exclude-standard'];\n\n\t\t\t\t// Batch the pathspecs to stay under the command-line length limit (a single batch when unscoped).\n\t\t\t\t// Reserve the prefix and a per-arg overhead (separator + possible quoting), so neither a run of\n\t\t\t\t// long paths nor many short ones can push a batch past the OS limit.\n\t\t\t\tlet batches: Iterable<readonly string[]> = [[]];\n\t\t\t\tif (pathspecs != null) {\n\t\t\t\t\tconst perArgOverhead = 3;\n\t\t\t\t\tconst prefixLength = [...prefix, '--'].reduce((sum, arg) => sum + arg.length + perArgOverhead, 0);\n\t\t\t\t\tbatches = chunkByStringLength(pathspecs, maxGitCliLength - prefixLength, perArgOverhead);\n\t\t\t\t}\n\n\t\t\t\tconst seen = new Set<string>();\n\t\t\t\tconst files: GitFile[] = [];\n\n\t\t\t\tfor (const batch of batches) {\n\t\t\t\t\tconst result = await this.git.run(\n\t\t\t\t\t\t{ cwd: repoPath, cancellation: signal, errors: 'throw', correlationKey: correlationKey },\n\t\t\t\t\t\t...prefix,\n\t\t\t\t\t\t...(pathspecs != null ? ['--', ...batch] : []),\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!result.stdout) continue;\n\n\t\t\t\t\tfor (const line of iterateByDelimiter(result.stdout, '\\0')) {\n\t\t\t\t\t\tif (!line.length || seen.has(line)) continue;\n\n\t\t\t\t\t\tseen.add(line);\n\t\t\t\t\t\tfiles.push({ path: line, repoPath: repoPath, status: GitFileWorkingTreeStatus.Untracked });\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tscope?.addExitInfo(files.length ? `${String(files.length)} untracked file(s)` : 'no untracked files');\n\t\t\t\treturn files;\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -92,8 +92,6 @@ var TagsGitSubProvider = class {
|
|
|
92
92
|
if (message != null && message.length > 0) args.push("-m", message);
|
|
93
93
|
try {
|
|
94
94
|
await this.git.run({ cwd: repoPath }, ...args);
|
|
95
|
-
this.context.hooks?.cache?.onReset?.(repoPath, "tags");
|
|
96
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, ["tags"]);
|
|
97
95
|
} catch (ex) {
|
|
98
96
|
throw getGitCommandError("tag", ex, (reason) => new TagError({
|
|
99
97
|
reason,
|
|
@@ -104,6 +102,9 @@ var TagsGitSubProvider = class {
|
|
|
104
102
|
args
|
|
105
103
|
}
|
|
106
104
|
}, ex));
|
|
105
|
+
} finally {
|
|
106
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "tags");
|
|
107
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["tags"]);
|
|
107
108
|
}
|
|
108
109
|
}
|
|
109
110
|
async deleteTag(repoPath, name) {
|
|
@@ -114,8 +115,6 @@ var TagsGitSubProvider = class {
|
|
|
114
115
|
];
|
|
115
116
|
try {
|
|
116
117
|
await this.git.run({ cwd: repoPath }, ...args);
|
|
117
|
-
this.context.hooks?.cache?.onReset?.(repoPath, "tags");
|
|
118
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, ["tags"]);
|
|
119
118
|
} catch (ex) {
|
|
120
119
|
throw getGitCommandError("tag", ex, (reason) => new TagError({
|
|
121
120
|
reason,
|
|
@@ -126,6 +125,9 @@ var TagsGitSubProvider = class {
|
|
|
126
125
|
args
|
|
127
126
|
}
|
|
128
127
|
}, ex));
|
|
128
|
+
} finally {
|
|
129
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "tags");
|
|
130
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["tags"]);
|
|
129
131
|
}
|
|
130
132
|
}
|
|
131
133
|
async pushTag(repoPath, name, remote, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tags.js","names":[],"sources":["../../../../git-cli/src/providers/tags.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { TagError } from '@gitlens/git/errors.js';\nimport { GitTag } from '@gitlens/git/models/tag.js';\nimport type { GitTagsSubProvider } from '@gitlens/git/providers/tags.js';\nimport type { TagSortOptions } from '@gitlens/git/utils/sorting.js';\nimport { sortTags } from '@gitlens/git/utils/sorting.js';\nimport { ensureArray, filterMap } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport type { PagedResult, PagingOptions } from '@gitlens/utils/paging.js';\nimport { emptyPagedResult } from '@gitlens/utils/paging.js';\nimport { maybeStopWatch } from '@gitlens/utils/stopwatch.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { GitResult } from '../exec/exec.types.js';\nimport type { Git, GitError } from '../exec/git.js';\nimport { getGitCommandError, gitConfigsBranch } from '../exec/git.js';\n\nexport class TagsGitSubProvider implements GitTagsSubProvider {\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@debug()\n\tasync getTag(repoPath: string, name: string, cancellation?: AbortSignal): Promise<GitTag | undefined> {\n\t\tconst {\n\t\t\tvalues: [tag],\n\t\t} = await this.getTags(repoPath, { filter: t => t.name === name }, cancellation);\n\t\treturn tag;\n\t}\n\n\t@debug({ args: repoPath => ({ repoPath: repoPath }) })\n\tasync getTags(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tfilter?: (t: GitTag) => boolean;\n\t\t\tpaging?: PagingOptions;\n\t\t\tsort?: boolean | TagSortOptions;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PagedResult<GitTag>> {\n\t\tif (!repoPath) return emptyPagedResult;\n\n\t\tconst scope = getScopedLogger();\n\n\t\tlet tagsResult = await this.cache.getTags(\n\t\t\trepoPath,\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\ttry {\n\t\t\t\t\tconst records = await this.provider.refs.getRefs(commonPath, signal);\n\t\t\t\t\tif (!records.length) return emptyPagedResult;\n\n\t\t\t\t\tusing sw = maybeStopWatch(scope, { log: { onlyExit: true, level: 'debug' } });\n\n\t\t\t\t\tconst tags: GitTag[] = [];\n\n\t\t\t\t\tfor (const record of records) {\n\t\t\t\t\t\tconst fullName = record.name;\n\t\t\t\t\t\tif (!fullName.startsWith('refs/tags/')) continue;\n\n\t\t\t\t\t\t// Annotated tags: peeledObjectname is the commit SHA; objectname is the tag-object SHA.\n\t\t\t\t\t\t// Lightweight tags: peeledObjectname is empty; objectname is already the commit SHA.\n\t\t\t\t\t\tconst annotated = Boolean(record.peeledObjectname);\n\t\t\t\t\t\tconst sha = record.peeledObjectname || record.objectname;\n\n\t\t\t\t\t\ttags.push(\n\t\t\t\t\t\t\tnew GitTag(\n\t\t\t\t\t\t\t\tcommonPath,\n\t\t\t\t\t\t\t\tfullName,\n\t\t\t\t\t\t\t\tsha,\n\t\t\t\t\t\t\t\trecord.subject,\n\t\t\t\t\t\t\t\trecord.creatorDate ? new Date(record.creatorDate) : undefined,\n\t\t\t\t\t\t\t\trecord.authorDate ? new Date(record.authorDate) : undefined,\n\t\t\t\t\t\t\t\tannotated,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tsw?.stop({ suffix: ` parsed ${String(tags.length)} tags` });\n\n\t\t\t\t\treturn { values: tags };\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tscope?.error(ex);\n\t\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\t\treturn emptyPagedResult;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\n\t\tif (options?.filter != null) {\n\t\t\ttagsResult = {\n\t\t\t\t...tagsResult,\n\t\t\t\tvalues: tagsResult.values.filter(options.filter),\n\t\t\t};\n\t\t}\n\n\t\tif (options?.sort) {\n\t\t\tsortTags(tagsResult.values, typeof options.sort === 'boolean' ? undefined : options.sort);\n\t\t}\n\n\t\treturn tagsResult;\n\t}\n\n\t@debug()\n\tasync getTagsWithCommit(\n\t\trepoPath: string,\n\t\tsha: string,\n\t\toptions?: { commitDate?: Date; mode?: 'contains' | 'pointsAt' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<string[]> {\n\t\tconst result = await this.tagsContainingCore(repoPath, sha, options, cancellation);\n\t\tif (!result.stdout) return [];\n\n\t\treturn filterMap(result.stdout.split('\\n'), b => b.trim() || undefined);\n\t}\n\n\tprivate async tagsContainingCore(\n\t\trepoPath: string,\n\t\tsha: string,\n\t\toptions?: { mode?: 'contains' | 'pointsAt' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitResult> {\n\t\tconst params: string[] = ['tag', '--format=%(refname:short)'];\n\t\tparams.push(options?.mode === 'pointsAt' ? `--points-at=${sha}` : `--contains=${sha}`);\n\n\t\treturn this.git.run(\n\t\t\t{\n\t\t\t\tcwd: repoPath,\n\t\t\t\tcancellation: cancellation,\n\t\t\t\tconfigs: gitConfigsBranch,\n\t\t\t\terrors: 'ignore',\n\t\t\t},\n\t\t\t...params,\n\t\t);\n\t}\n\n\t@debug()\n\tasync createTag(repoPath: string, name: string, sha: string, message?: string): Promise<void> {\n\t\tconst args = ['tag', name, sha];\n\t\tif (message != null && message.length > 0) {\n\t\t\targs.push('-m', message);\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'tags');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['tags']);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{ reason: reason, action: 'create', tag: name, 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}\n\t}\n\n\t@debug()\n\tasync deleteTag(repoPath: string, name: string): Promise<void> {\n\t\tconst args = ['tag', '-d', name];\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'tags');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['tags']);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{ reason: reason, action: 'delete', tag: name, 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}\n\t}\n\n\t@debug()\n\tasync pushTag(\n\t\trepoPath: string,\n\t\tname: string | string[],\n\t\tremote: string,\n\t\toptions?: { force?: boolean },\n\t): Promise<void> {\n\t\tconst names = ensureArray(name);\n\t\tconst args = ['push'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t}\n\n\t\targs.push(remote, ...names.map(n => `refs/tags/${n}`));\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treason: reason,\n\t\t\t\t\t\t\taction: 'push',\n\t\t\t\t\t\t\ttag: names.join(', '),\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\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"tags.js","names":[],"sources":["../../../../git-cli/src/providers/tags.ts"],"sourcesContent":["import type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { TagError } from '@gitlens/git/errors.js';\nimport { GitTag } from '@gitlens/git/models/tag.js';\nimport type { GitTagsSubProvider } from '@gitlens/git/providers/tags.js';\nimport type { TagSortOptions } from '@gitlens/git/utils/sorting.js';\nimport { sortTags } from '@gitlens/git/utils/sorting.js';\nimport { ensureArray, filterMap } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport type { PagedResult, PagingOptions } from '@gitlens/utils/paging.js';\nimport { emptyPagedResult } from '@gitlens/utils/paging.js';\nimport { maybeStopWatch } from '@gitlens/utils/stopwatch.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { GitResult } from '../exec/exec.types.js';\nimport type { Git, GitError } from '../exec/git.js';\nimport { getGitCommandError, gitConfigsBranch } from '../exec/git.js';\n\nexport class TagsGitSubProvider implements GitTagsSubProvider {\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@debug()\n\tasync getTag(repoPath: string, name: string, cancellation?: AbortSignal): Promise<GitTag | undefined> {\n\t\tconst {\n\t\t\tvalues: [tag],\n\t\t} = await this.getTags(repoPath, { filter: t => t.name === name }, cancellation);\n\t\treturn tag;\n\t}\n\n\t@debug({ args: repoPath => ({ repoPath: repoPath }) })\n\tasync getTags(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tfilter?: (t: GitTag) => boolean;\n\t\t\tpaging?: PagingOptions;\n\t\t\tsort?: boolean | TagSortOptions;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<PagedResult<GitTag>> {\n\t\tif (!repoPath) return emptyPagedResult;\n\n\t\tconst scope = getScopedLogger();\n\n\t\tlet tagsResult = await this.cache.getTags(\n\t\t\trepoPath,\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\ttry {\n\t\t\t\t\tconst records = await this.provider.refs.getRefs(commonPath, signal);\n\t\t\t\t\tif (!records.length) return emptyPagedResult;\n\n\t\t\t\t\tusing sw = maybeStopWatch(scope, { log: { onlyExit: true, level: 'debug' } });\n\n\t\t\t\t\tconst tags: GitTag[] = [];\n\n\t\t\t\t\tfor (const record of records) {\n\t\t\t\t\t\tconst fullName = record.name;\n\t\t\t\t\t\tif (!fullName.startsWith('refs/tags/')) continue;\n\n\t\t\t\t\t\t// Annotated tags: peeledObjectname is the commit SHA; objectname is the tag-object SHA.\n\t\t\t\t\t\t// Lightweight tags: peeledObjectname is empty; objectname is already the commit SHA.\n\t\t\t\t\t\tconst annotated = Boolean(record.peeledObjectname);\n\t\t\t\t\t\tconst sha = record.peeledObjectname || record.objectname;\n\n\t\t\t\t\t\ttags.push(\n\t\t\t\t\t\t\tnew GitTag(\n\t\t\t\t\t\t\t\tcommonPath,\n\t\t\t\t\t\t\t\tfullName,\n\t\t\t\t\t\t\t\tsha,\n\t\t\t\t\t\t\t\trecord.subject,\n\t\t\t\t\t\t\t\trecord.creatorDate ? new Date(record.creatorDate) : undefined,\n\t\t\t\t\t\t\t\trecord.authorDate ? new Date(record.authorDate) : undefined,\n\t\t\t\t\t\t\t\tannotated,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tsw?.stop({ suffix: ` parsed ${String(tags.length)} tags` });\n\n\t\t\t\t\treturn { values: tags };\n\t\t\t\t} catch (ex) {\n\t\t\t\t\tscope?.error(ex);\n\t\t\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\t\t\treturn emptyPagedResult;\n\t\t\t\t}\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\n\t\tif (options?.filter != null) {\n\t\t\ttagsResult = {\n\t\t\t\t...tagsResult,\n\t\t\t\tvalues: tagsResult.values.filter(options.filter),\n\t\t\t};\n\t\t}\n\n\t\tif (options?.sort) {\n\t\t\tsortTags(tagsResult.values, typeof options.sort === 'boolean' ? undefined : options.sort);\n\t\t}\n\n\t\treturn tagsResult;\n\t}\n\n\t@debug()\n\tasync getTagsWithCommit(\n\t\trepoPath: string,\n\t\tsha: string,\n\t\toptions?: { commitDate?: Date; mode?: 'contains' | 'pointsAt' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<string[]> {\n\t\tconst result = await this.tagsContainingCore(repoPath, sha, options, cancellation);\n\t\tif (!result.stdout) return [];\n\n\t\treturn filterMap(result.stdout.split('\\n'), b => b.trim() || undefined);\n\t}\n\n\tprivate async tagsContainingCore(\n\t\trepoPath: string,\n\t\tsha: string,\n\t\toptions?: { mode?: 'contains' | 'pointsAt' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitResult> {\n\t\tconst params: string[] = ['tag', '--format=%(refname:short)'];\n\t\tparams.push(options?.mode === 'pointsAt' ? `--points-at=${sha}` : `--contains=${sha}`);\n\n\t\treturn this.git.run(\n\t\t\t{\n\t\t\t\tcwd: repoPath,\n\t\t\t\tcancellation: cancellation,\n\t\t\t\tconfigs: gitConfigsBranch,\n\t\t\t\terrors: 'ignore',\n\t\t\t},\n\t\t\t...params,\n\t\t);\n\t}\n\n\t@debug()\n\tasync createTag(repoPath: string, name: string, sha: string, message?: string): Promise<void> {\n\t\tconst args = ['tag', name, sha];\n\t\tif (message != null && message.length > 0) {\n\t\t\targs.push('-m', message);\n\t\t}\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{ reason: reason, action: 'create', tag: name, 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\tthis.context.hooks?.cache?.onReset?.(repoPath, 'tags');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['tags']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync deleteTag(repoPath: string, name: string): Promise<void> {\n\t\tconst args = ['tag', '-d', name];\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{ reason: reason, action: 'delete', tag: name, 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\tthis.context.hooks?.cache?.onReset?.(repoPath, 'tags');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['tags']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync pushTag(\n\t\trepoPath: string,\n\t\tname: string | string[],\n\t\tremote: string,\n\t\toptions?: { force?: boolean },\n\t): Promise<void> {\n\t\tconst names = ensureArray(name);\n\t\tconst args = ['push'];\n\t\tif (options?.force) {\n\t\t\targs.push('--force');\n\t\t}\n\n\t\targs.push(remote, ...names.map(n => `refs/tags/${n}`));\n\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t} catch (ex) {\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'tag',\n\t\t\t\tex as GitError,\n\t\t\t\treason =>\n\t\t\t\t\tnew TagError(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treason: reason,\n\t\t\t\t\t\t\taction: 'push',\n\t\t\t\t\t\t\ttag: names.join(', '),\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\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -33,6 +33,7 @@ export declare class WorktreesGitSubProvider implements GitWorktreesSubProvider
|
|
|
33
33
|
}, runOptions?: GitOperationRunOptions): Promise<GitWorktree | undefined>;
|
|
34
34
|
getWorktree(repoPath: string, predicate: (w: GitWorktree) => boolean, cancellation?: AbortSignal): Promise<GitWorktree | undefined>;
|
|
35
35
|
getWorktrees(repoPath: string, cancellation?: AbortSignal): Promise<GitWorktree[]>;
|
|
36
|
+
private withLockReason;
|
|
36
37
|
getWorktreesDefaultUri(repoPath: string): Uri | undefined;
|
|
37
38
|
/**
|
|
38
39
|
* Deletes a worktree (`git worktree remove`). Pass `force: 'locked'` to also override a locked worktree.
|
|
@@ -3,12 +3,15 @@ import { getScopedLogger } from "../../utils/logger.scoped.js";
|
|
|
3
3
|
import { getSettledValue } from "../../utils/promise.js";
|
|
4
4
|
import { debug } from "../../utils/decorators/log.js";
|
|
5
5
|
import { fileUri, toFsPath } from "../../utils/uri.js";
|
|
6
|
-
import { basename, normalizePath } from "../../utils/path.js";
|
|
6
|
+
import { basename as basename$1, normalizePath } from "../../utils/path.js";
|
|
7
7
|
import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
|
|
8
8
|
import { WorktreeCreateError, WorktreeDeleteError } from "../../git/errors.js";
|
|
9
|
+
import { mayWriteTracking } from "../exec/commandClassifier.js";
|
|
9
10
|
import { isWindows } from "../../utils/env/node/platform.js";
|
|
10
11
|
import { GitErrors, getGitCommandError } from "../exec/git.js";
|
|
12
|
+
import { GitWorktree } from "../../git/models/worktree.js";
|
|
11
13
|
import { parseGitWorktrees } from "../parsers/worktreeParser.js";
|
|
14
|
+
import { join, resolve } from "path";
|
|
12
15
|
import * as l10n from "@vscode/l10n";
|
|
13
16
|
import { exec } from "child_process";
|
|
14
17
|
import { promises } from "fs";
|
|
@@ -47,8 +50,6 @@ var WorktreesGitSubProvider = class {
|
|
|
47
50
|
...runOptions
|
|
48
51
|
}, ...args);
|
|
49
52
|
if (options?.createBranch) this.cache.deleteBaseBranchName(repoPath, options.createBranch);
|
|
50
|
-
this.context.hooks?.cache?.onReset?.(repoPath, ...options?.createBranch ? ["branches", "worktrees"] : ["worktrees"]);
|
|
51
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, options?.createBranch ? ["worktrees", "heads"] : ["worktrees"]);
|
|
52
53
|
} catch (ex) {
|
|
53
54
|
scope?.error(ex);
|
|
54
55
|
if (isCancellationError(ex)) throw ex;
|
|
@@ -59,6 +60,11 @@ var WorktreesGitSubProvider = class {
|
|
|
59
60
|
args
|
|
60
61
|
}
|
|
61
62
|
}, ex));
|
|
63
|
+
} finally {
|
|
64
|
+
this.context.hooks?.cache?.onReset?.(repoPath, ...options?.createBranch ? ["branches", "worktrees"] : ["worktrees"]);
|
|
65
|
+
const changes = options?.createBranch ? ["worktrees", "heads"] : ["worktrees"];
|
|
66
|
+
if (options?.createBranch && mayWriteTracking(options.commitish, options.noTracking)) changes.unshift("config");
|
|
67
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, changes);
|
|
62
68
|
}
|
|
63
69
|
}
|
|
64
70
|
async createWorktreeWithResult(repoPath, path, options, runOptions) {
|
|
@@ -83,12 +89,27 @@ var WorktreesGitSubProvider = class {
|
|
|
83
89
|
if (folder == null) return void 0;
|
|
84
90
|
return {
|
|
85
91
|
uri: fileUri(folder.path),
|
|
86
|
-
name: basename(folder.path)
|
|
92
|
+
name: basename$1(folder.path)
|
|
87
93
|
};
|
|
88
94
|
} : void 0;
|
|
89
|
-
|
|
95
|
+
const worktrees = parseGitWorktrees(getSettledValue(dataResult)?.stdout, commonPath, getSettledValue(branchesResult)?.values ?? [], getWorkspaceFolder);
|
|
96
|
+
if (await this.git.supports("git:worktree:list:lock-reason")) return worktrees;
|
|
97
|
+
return Promise.all(worktrees.map((w) => this.withLockReason(w)));
|
|
90
98
|
}, cancellation);
|
|
91
99
|
}
|
|
100
|
+
async withLockReason(worktree) {
|
|
101
|
+
if (worktree.locked !== true || worktree.isDefault || worktree.type === "bare") return worktree;
|
|
102
|
+
try {
|
|
103
|
+
const dotGit = join(worktree.uri.fsPath, ".git");
|
|
104
|
+
const match = /^gitdir:\s*(.+?)\s*$/m.exec(await promises.readFile(dotGit, "utf8"));
|
|
105
|
+
if (match == null) return worktree;
|
|
106
|
+
const reason = (await promises.readFile(join(resolve(worktree.uri.fsPath, match[1]), "locked"), "utf8")).trim();
|
|
107
|
+
if (!reason) return worktree;
|
|
108
|
+
return new GitWorktree(worktree.isDefault, worktree.type, worktree.repoPath, worktree.uri, reason, worktree.prunable, worktree.sha, worktree.branch, worktree.workspaceFolder);
|
|
109
|
+
} catch {
|
|
110
|
+
return worktree;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
92
113
|
getWorktreesDefaultUri(repoPath) {
|
|
93
114
|
return this.context.workspace?.getWorktreeDefaultUri?.(repoPath);
|
|
94
115
|
}
|
|
@@ -175,11 +196,9 @@ var WorktreesGitSubProvider = class {
|
|
|
175
196
|
}
|
|
176
197
|
throw gitError;
|
|
177
198
|
} finally {
|
|
178
|
-
if (deleted)
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
182
|
-
}
|
|
199
|
+
if (deleted) this.cache.unregisterRepoPath(pathStr);
|
|
200
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "worktrees");
|
|
201
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
183
202
|
}
|
|
184
203
|
}
|
|
185
204
|
async pruneWorktrees(repoPath, options) {
|
|
@@ -187,16 +206,19 @@ var WorktreesGitSubProvider = class {
|
|
|
187
206
|
const before = await this.listWorktreePaths(repoPath);
|
|
188
207
|
const args = ["worktree", "prune"];
|
|
189
208
|
if (options?.expire) args.push("--expire", options.expire);
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
209
|
+
try {
|
|
210
|
+
await this.git.run({
|
|
211
|
+
cwd: repoPath,
|
|
212
|
+
errors: "throw"
|
|
213
|
+
}, ...args);
|
|
214
|
+
const after = await this.listWorktreePaths(repoPath);
|
|
215
|
+
if (before != null && after != null) {
|
|
216
|
+
for (const path of before) if (!after.has(path)) this.cache.unregisterRepoPath(path);
|
|
217
|
+
}
|
|
218
|
+
} finally {
|
|
219
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "worktrees");
|
|
220
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
197
221
|
}
|
|
198
|
-
this.context.hooks?.cache?.onReset?.(repoPath, "worktrees");
|
|
199
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
200
222
|
}
|
|
201
223
|
/**
|
|
202
224
|
* Raw worktree paths currently known to git (`worktree <path>` lines from `--porcelain`), normalized the
|
|
@@ -219,21 +241,28 @@ var WorktreesGitSubProvider = class {
|
|
|
219
241
|
const args = ["worktree", "lock"];
|
|
220
242
|
if (options?.reason) args.push("--reason", options.reason);
|
|
221
243
|
args.push(normalizePath(toFsPath(path)));
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
244
|
+
try {
|
|
245
|
+
await this.git.run({
|
|
246
|
+
cwd: repoPath,
|
|
247
|
+
errors: "throw"
|
|
248
|
+
}, ...args);
|
|
249
|
+
} finally {
|
|
250
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "worktrees");
|
|
251
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
252
|
+
}
|
|
228
253
|
}
|
|
229
254
|
async unlockWorktree(repoPath, path) {
|
|
230
255
|
await this.git.ensureSupports("git:worktrees", (requiredVersion, installedVersion) => l10n.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.", requiredVersion, installedVersion));
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
256
|
+
const pathStr = normalizePath(toFsPath(path));
|
|
257
|
+
try {
|
|
258
|
+
await this.git.run({
|
|
259
|
+
cwd: repoPath,
|
|
260
|
+
errors: "throw"
|
|
261
|
+
}, "worktree", "unlock", pathStr);
|
|
262
|
+
} finally {
|
|
263
|
+
this.context.hooks?.cache?.onReset?.(repoPath, "worktrees");
|
|
264
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["worktrees"]);
|
|
265
|
+
}
|
|
237
266
|
}
|
|
238
267
|
};
|
|
239
268
|
__decorate([debug()], WorktreesGitSubProvider.prototype, "createWorktree", null);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktrees.js","names":["fs"],"sources":["../../../../git-cli/src/providers/worktrees.ts"],"sourcesContent":["import { exec } from 'child_process';\nimport { promises as fs } from 'fs';\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 { GitWorktree, WorkspaceFolderResolver } 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, normalizePath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { Git, GitError } from '../exec/git.js';\nimport { getGitCommandError, GitErrors } 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\nexport class WorktreesGitSubProvider implements GitWorktreesSubProvider {\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/**\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\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\n\t\t\tif (options?.createBranch) {\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, options.createBranch);\n\t\t\t}\n\n\t\t\tthis.context.hooks?.cache?.onReset?.(\n\t\t\t\trepoPath,\n\t\t\t\t...(options?.createBranch ? (['branches', 'worktrees'] as const) : (['worktrees'] as const)),\n\t\t\t);\n\t\t\tthis.context.hooks?.repository?.onChanged?.(\n\t\t\t\trepoPath,\n\t\t\t\toptions?.createBranch ? ['worktrees', 'heads'] : ['worktrees'],\n\t\t\t);\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// A cancelled or timed-out checkout is not git refusing the worktree\n\t\t\tif (isCancellationError(ex)) throw ex;\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}\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(repoPath, w => normalizePath(w.path) === normalized, runOptions?.cancellation);\n\t}\n\n\t@debug()\n\tasync getWorktree(\n\t\trepoPath: string,\n\t\tpredicate: (w: GitWorktree) => boolean,\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree | undefined> {\n\t\treturn (await this.getWorktrees(repoPath, cancellation)).find(predicate);\n\t}\n\n\t@debug()\n\tasync getWorktrees(repoPath: string, cancellation?: AbortSignal): Promise<GitWorktree[]> {\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\treturn this.cache.getWorktrees(\n\t\t\trepoPath,\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 [dataResult, branchesResult] = await Promise.allSettled([\n\t\t\t\t\tthis.git.run({ cwd: commonPath, cancellation: signal }, 'worktree', 'list', '--porcelain'),\n\t\t\t\t\tthis.provider.branches.getBranches(commonPath, undefined, signal),\n\t\t\t\t]);\n\n\t\t\t\tif (dataResult.status === 'rejected') {\n\t\t\t\t\t// Don't cache a bogus empty result for a transient command failure — retry on next access.\n\t\t\t\t\tcacheable.invalidate();\n\t\t\t\t}\n\n\t\t\t\tconst getWorkspaceFolder: WorkspaceFolderResolver | undefined = this.context.workspace\n\t\t\t\t\t? uri => {\n\t\t\t\t\t\t\tconst folder = this.context.workspace!.getFolder(uri.fsPath);\n\t\t\t\t\t\t\tif (folder == null) return undefined;\n\t\t\t\t\t\t\treturn { uri: fileUri(folder.path), name: basename(folder.path) };\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined;\n\n\t\t\t\treturn parseGitWorktrees(\n\t\t\t\t\tgetSettledValue(dataResult)?.stdout,\n\t\t\t\t\tcommonPath,\n\t\t\t\t\tgetSettledValue(branchesResult)?.values ?? [],\n\t\t\t\t\tgetWorkspaceFolder,\n\t\t\t\t);\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\n\t}\n\n\t@debug()\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`) is not git refusing it, and\n\t\t\t// wrapping it would hand the caller a `WorktreeDeleteError` whose `original` is no `GitError` at all\n\t\t\tif (isCancellationError(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\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t\t}\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\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\n\t\tconst after = await this.listWorktreePaths(repoPath);\n\n\t\t// Order matters (see `deleteWorktree`): unregister before emitting the repo-level change so any\n\t\t// listener that re-queries worktree-aware state sees the registry already updated.\n\t\tif (before != null && after != null) {\n\t\t\tfor (const path of before) {\n\t\t\t\tif (!after.has(path)) {\n\t\t\t\t\tthis.cache.unregisterRepoPath(path);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\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\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, ...args);\n\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\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\tawait this.git.run({ cwd: repoPath, errors: 'throw' }, 'worktree', 'unlock', normalizePath(toFsPath(path)));\n\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAuBA,SAAS,cAAc,IAAkC;CACxD,OAAO,UAAU,qBAAqB,KAAK,GAAG,UAAU,GAAG,UAAU,GAAG,WAAW,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,KAAA;AACvG;AAEA,IAAa,0BAAb,MAAwE;CAErD;CACA;CACA;CACA;CAJlB,YACC,SACA,KACA,OACA,UACC;EAJgB,KAAA,UAAA;EACA,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;CACf;;;;;CAMH,MACM,eACL,UACA,MACA,SAOA,YACgB;EAChB,MAAM,QAAQ,gBAAgB;EAE9B,MAAM,OAAO,CAAC,YAAY,KAAK;EAC/B,IAAI,SAAS,OACZ,KAAK,KAAK,SAAS;EAEpB,IAAI,SAAS,cACZ,KAAK,KAAK,MAAM,QAAQ,YAAY;EAErC,IAAI,SAAS,gBAAgB,QAAQ,YACpC,KAAK,KAAK,YAAY;EAEvB,IAAI,SAAS,QACZ,KAAK,KAAK,UAAU;EAErB,KAAK,KAAK,IAAI;EACd,IAAI,SAAS,WACZ,KAAK,KAAK,QAAQ,SAAS;EAG5B,IAAI;GACH,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,GAAG;GAAW,GAAG,GAAG,IAAI;GAE5D,IAAI,SAAS,cAEZ,KAAK,MAAM,qBAAqB,UAAU,QAAQ,YAAY;GAG/D,KAAK,QAAQ,OAAO,OAAO,UAC1B,UACA,GAAI,SAAS,eAAgB,CAAC,YAAY,WAAW,IAAe,CAAC,WAAW,CACjF;GACA,KAAK,QAAQ,OAAO,YAAY,YAC/B,UACA,SAAS,eAAe,CAAC,aAAa,OAAO,IAAI,CAAC,WAAW,CAC9D;EACD,SAAS,IAAI;GACZ,OAAO,MAAM,EAAE;GAEf,IAAI,oBAAoB,EAAE,GAAG,MAAM;GAEnC,MAAM,mBACL,mBACA,KACA,WACC,IAAI,oBACH;IAAU;IAAQ,YAAY;KAAY;KAAgB;IAAK;GAAE,GACjE,EACD,CACF;EACD;CACD;CAEA,MAAM,yBACL,UACA,MACA,SAOA,YACmC;EACnC,MAAM,KAAK,eAAe,UAAU,MAAM,SAAS,UAAU;EAC7D,MAAM,aAAa,cAAc,IAAI;EACrC,OAAO,KAAK,YAAY,WAAU,MAAK,cAAc,EAAE,IAAI,MAAM,YAAY,YAAY,YAAY;CACtG;CAEA,MACM,YACL,UACA,WACA,cACmC;EACnC,QAAQ,MAAM,KAAK,aAAa,UAAU,YAAY,EAAA,CAAG,KAAK,SAAS;CACxE;CAEA,MACM,aAAa,UAAkB,cAAoD;EACxF,MAAM,KAAK,IAAI,eAAe,kBAAkB,iBAAiB,qBAChE,KAAK,EACJ,+JACA,iBACA,gBACD,CACD;EAEA,OAAO,KAAK,MAAM,aACjB,UACA,OAAO,YAAY,WAAW,WAAW;GAExC,WAAW;GACX,MAAM,CAAC,YAAY,kBAAkB,MAAM,QAAQ,WAAW,CAC7D,KAAK,IAAI,IAAI;IAAE,KAAK;IAAY,cAAc;GAAO,GAAG,YAAY,QAAQ,aAAa,GACzF,KAAK,SAAS,SAAS,YAAY,YAAY,KAAA,GAAW,MAAM,CACjE,CAAC;GAED,IAAI,WAAW,WAAW,YAEzB,UAAU,WAAW;GAGtB,MAAM,qBAA0D,KAAK,QAAQ,aAC1E,QAAO;IACP,MAAM,SAAS,KAAK,QAAQ,UAAW,UAAU,IAAI,MAAM;IAC3D,IAAI,UAAU,MAAM,OAAO,KAAA;IAC3B,OAAO;KAAE,KAAK,QAAQ,OAAO,IAAI;KAAG,MAAM,SAAS,OAAO,IAAI;IAAE;GACjE,IACC,KAAA;GAEH,OAAO,kBACN,gBAAgB,UAAU,CAAC,EAAE,QAC7B,YACA,gBAAgB,cAAc,CAAC,EAAE,UAAU,CAAC,GAC5C,kBACD;EACD,GACA,YACD;CACD;CAEA,uBACuB,UAAmC;EACzD,OAAO,KAAK,QAAQ,WAAW,wBAAwB,QAAQ;CAChE;;;;;;;;;;;;CAaA,MACM,eACL,UACA,MACA,SACA,YACgB;EAChB,MAAM,QAAQ,gBAAgB;EAE9B,MAAM,KAAK,IAAI,eAAe,kBAAkB,iBAAiB,qBAChE,KAAK,EACJ,6JACA,iBACA,gBACD,CACD;EAEA,MAAM,OAAO,CAAC,YAAY,QAAQ;EAClC,IAAI,SAAS,OAAO;GACnB,KAAK,KAAK,SAAS;GAEnB,IAAI,QAAQ,UAAU,UACrB,KAAK,KAAK,SAAS;EAErB;EAEA,MAAM,UAAU,cAAc,SAAS,IAAI,CAAC;EAC5C,KAAK,KAAK,OAAO;EAEjB,IAAI,UAAU;EACd,IAAI;GACH,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,QAAQ;IAAS,GAAG;GAAW,GAAG,GAAG,IAAI;GAC7E,UAAU;EACX,SAAS,IAAI;GACZ,OAAO,MAAM,EAAE;GAGf,IAAI,oBAAoB,EAAE,GAAG,MAAM;GAEnC,MAAM,WAAW,mBAChB,mBACA,KACA,WACC,IAAI,oBACH;IACS;IACR,YAAY,WAAW,WAAW,cAAc,EAAc,IAAI,KAAA;IAClE,YAAY;KAAY;KAAgB;IAAK;GAC9C,GACA,EACD,CACF;GAEA,IAAI,SAAS,QAAQ,WAAW,qBAAqB;IACpD,OAAO,KACN,oCAAoC,QAAQ,6DAC7C;IACA,IAAI;KACH,MAAMA,SAAG,GAAG,SAAS;MAAE,OAAO;MAAM,WAAW;KAAK,CAAC;KACrD,UAAU;KACV;IACD,SAAS,IAAI;KACZ,IAAI,WAAW;MACd,MAAM,QAAQ,kDAAkD,KAAM,GAAgB,OAAO;MAC7F,IAAI,SAAS,MAAM;OAClB,OAAO,KACN,8BAA8B,QAAQ,4DACvC;OAIA,SAAS,mBAAmB,SAAiB;QAC5C,OAAO,IAAI,SAAS,SAAS,WAAW;SACvC,KAAK,QAAQ,QAAQ,KAAK,IAAI,QAAQ,WAAW;UAChD,IAAI,IACH,OAAO,cAAc,QAAQ,KAAK,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;eACjD,IAAI,QACV,OAAO,IAAI,MAAM,MAAM,CAAC;eAExB,QAAQ,MAAM;SAEhB,CAAC;QACF,CAAC;OACF;OAEA,MAAM,GAAG,QAAQ;OACjB,IAAI;QACH,MAAM,mBAAmB,IAAI;QAC7B,MAAMA,SAAG,GAAG,SAAS;SAAE,OAAO;SAAM,WAAW;SAAM,YAAY;SAAG,YAAY;QAAE,CAAC;QACnF,UAAU;QACV;OACD,SAAS,IAAI;QACZ,OAAO,MAAM,IAAI,gCAAgC,QAAQ,wBAAwB;OAClF;MACD;KACD;IACD;GACD;GAEA,MAAM;EACP,UAAU;GACT,IAAI,SAAS;IAIZ,KAAK,MAAM,mBAAmB,OAAO;IACrC,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW;IAC1D,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,WAAW,CAAC;GACpE;EACD;CACD;CAEA,MACM,eAAe,UAAkB,SAA8C;EACpF,MAAM,KAAK,IAAI,eAAe,kBAAkB,iBAAiB,qBAChE,KAAK,EACJ,4JACA,iBACA,gBACD,CACD;EAEA,MAAM,SAAS,MAAM,KAAK,kBAAkB,QAAQ;EAEpD,MAAM,OAAO,CAAC,YAAY,OAAO;EACjC,IAAI,SAAS,QACZ,KAAK,KAAK,YAAY,QAAQ,MAAM;EAGrC,MAAM,KAAK,IAAI,IAAI;GAAE,KAAK;GAAU,QAAQ;EAAQ,GAAG,GAAG,IAAI;EAE9D,MAAM,QAAQ,MAAM,KAAK,kBAAkB,QAAQ;EAInD,IAAI,UAAU,QAAQ,SAAS,MACzB;QAAA,MAAM,QAAQ,QAClB,IAAI,CAAC,MAAM,IAAI,IAAI,GAClB,KAAK,MAAM,mBAAmB,IAAI;EAAA;EAKrC,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW;EAC1D,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,WAAW,CAAC;CACpE;;;;;;;CAQA,MAAc,kBAAkB,UAAoD;EACnF,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;GAAE,KAAK;GAAU,QAAQ;EAAS,GAAG,YAAY,QAAQ,aAAa;EAExG,IAAI,OAAO,WAAW,WAAW,YAAY,OAAO,aAAa,GAAG,OAAO,KAAA;EAE3E,MAAM,wBAAQ,IAAI,IAAY;EAC9B,KAAK,MAAM,QAAQ,OAAO,OAAO,MAAM,IAAI,GAC1C,IAAI,KAAK,WAAW,WAAW,GAC9B,MAAM,IAAI,cAAc,SAAS,KAAK,MAAM,CAAkB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;EAG1E,OAAO;CACR;CAEA,MACM,aAAa,UAAkB,MAAoB,SAA8C;EACtG,MAAM,KAAK,IAAI,eAAe,kBAAkB,iBAAiB,qBAChE,KAAK,EACJ,4JACA,iBACA,gBACD,CACD;EAEA,MAAM,OAAO,CAAC,YAAY,MAAM;EAChC,IAAI,SAAS,QACZ,KAAK,KAAK,YAAY,QAAQ,MAAM;EAErC,KAAK,KAAK,cAAc,SAAS,IAAI,CAAC,CAAC;EAEvC,MAAM,KAAK,IAAI,IAAI;GAAE,KAAK;GAAU,QAAQ;EAAQ,GAAG,GAAG,IAAI;EAE9D,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW;EAC1D,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,WAAW,CAAC;CACpE;CAEA,MACM,eAAe,UAAkB,MAAmC;EACzE,MAAM,KAAK,IAAI,eAAe,kBAAkB,iBAAiB,qBAChE,KAAK,EACJ,8JACA,iBACA,gBACD,CACD;EAEA,MAAM,KAAK,IAAI,IAAI;GAAE,KAAK;GAAU,QAAQ;EAAQ,GAAG,YAAY,UAAU,cAAc,SAAS,IAAI,CAAC,CAAC;EAE1G,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW;EAC1D,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,WAAW,CAAC;CACpE;AACD;AApWE,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,kBAAA,IAAA;AAmFN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,eAAA,IAAA;AASN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,gBAAA,IAAA;AA4CN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,0BAAA,IAAA;AAgBN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,kBAAA,IAAA;AAgHN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,kBAAA,IAAA;AAuDN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,gBAAA,IAAA;AAsBN,WAAA,CAAA,MAAM,CAAA,GAAA,wBAAA,WAAA,kBAAA,IAAA"}
|
|
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 { RepositoryChange } from '@gitlens/git/models/repository.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, normalizePath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.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 } 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\nexport class WorktreesGitSubProvider implements GitWorktreesSubProvider {\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/**\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\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\n\t\t\tif (options?.createBranch) {\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, options.createBranch);\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\t\t\t// A cancelled or timed-out checkout is not git refusing the worktree\n\t\t\tif (isCancellationError(ex)) throw ex;\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\tthis.context.hooks?.cache?.onReset?.(\n\t\t\t\trepoPath,\n\t\t\t\t...(options?.createBranch ? (['branches', 'worktrees'] as const) : (['worktrees'] as const)),\n\t\t\t);\n\t\t\tconst changes: RepositoryChange[] = options?.createBranch ? ['worktrees', 'heads'] : ['worktrees'];\n\t\t\tif (options?.createBranch && mayWriteTracking(options.commitish, options.noTracking)) {\n\t\t\t\tchanges.unshift('config');\n\t\t\t}\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, changes);\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(repoPath, w => normalizePath(w.path) === normalized, runOptions?.cancellation);\n\t}\n\n\t@debug()\n\tasync getWorktree(\n\t\trepoPath: string,\n\t\tpredicate: (w: GitWorktree) => boolean,\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitWorktree | undefined> {\n\t\treturn (await this.getWorktrees(repoPath, cancellation)).find(predicate);\n\t}\n\n\t@debug()\n\tasync getWorktrees(repoPath: string, cancellation?: AbortSignal): Promise<GitWorktree[]> {\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\treturn this.cache.getWorktrees(\n\t\t\trepoPath,\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 [dataResult, branchesResult] = await Promise.allSettled([\n\t\t\t\t\tthis.git.run({ cwd: commonPath, cancellation: signal }, 'worktree', 'list', '--porcelain'),\n\t\t\t\t\tthis.provider.branches.getBranches(commonPath, undefined, signal),\n\t\t\t\t]);\n\n\t\t\t\tif (dataResult.status === 'rejected') {\n\t\t\t\t\t// Don't cache a bogus empty result for a transient command failure — retry on next access.\n\t\t\t\t\tcacheable.invalidate();\n\t\t\t\t}\n\n\t\t\t\tconst getWorkspaceFolder: WorkspaceFolderResolver | undefined = this.context.workspace\n\t\t\t\t\t? uri => {\n\t\t\t\t\t\t\tconst folder = this.context.workspace!.getFolder(uri.fsPath);\n\t\t\t\t\t\t\tif (folder == null) return undefined;\n\t\t\t\t\t\t\treturn { uri: fileUri(folder.path), name: basename(folder.path) };\n\t\t\t\t\t\t}\n\t\t\t\t\t: undefined;\n\n\t\t\t\tconst worktrees = parseGitWorktrees(\n\t\t\t\t\tgetSettledValue(dataResult)?.stdout,\n\t\t\t\t\tcommonPath,\n\t\t\t\t\tgetSettledValue(branchesResult)?.values ?? [],\n\t\t\t\t\tgetWorkspaceFolder,\n\t\t\t\t);\n\n\t\t\t\t// Older git prints a bare `locked` even when a reason exists; recover it from the admin dir\n\t\t\t\tif (await this.git.supports('git:worktree:list:lock-reason')) return worktrees;\n\n\t\t\t\treturn Promise.all(worktrees.map(w => this.withLockReason(w)));\n\t\t\t},\n\t\t\tcancellation,\n\t\t);\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);\n\t\t} catch {\n\t\t\treturn worktree;\n\t\t}\n\t}\n\n\t@debug()\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`) is not git refusing it, and\n\t\t\t// wrapping it would hand the caller a `WorktreeDeleteError` whose `original` is no `GitError` at all\n\t\t\tif (isCancellationError(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']);\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']);\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\tthis.context.hooks?.cache?.onReset?.(repoPath, 'worktrees');\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, 'worktrees');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['worktrees']);\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { FileWatchingProvider } from "../git/watching/provider.js";
|
|
2
|
+
import { WatchPollingOptions } from "../git/watching/watchService.js";
|
|
2
3
|
import { GitLocation } from "./exec/locator.js";
|
|
3
4
|
import { CliGitProviderOptions } from "./cliGitProvider.js";
|
|
4
5
|
import { GitService } from "../git/service.js";
|
|
@@ -29,6 +30,11 @@ export interface CliGitServiceOptions {
|
|
|
29
30
|
* will watch repositories for changes (file creates, edits, deletes).
|
|
30
31
|
*/
|
|
31
32
|
watchingProvider?: FileWatchingProvider;
|
|
33
|
+
/**
|
|
34
|
+
* Polls in place of (or beside) the watchers {@link watchingProvider} reports it can't trust. When omitted, no
|
|
35
|
+
* watcher is asked.
|
|
36
|
+
*/
|
|
37
|
+
watchPolling?: WatchPollingOptions;
|
|
32
38
|
}
|
|
33
39
|
/**
|
|
34
40
|
* Creates a ready-to-use {@link GitService} backed by the CLI git provider.
|
package/dist/git-cli/service.js
CHANGED
|
@@ -22,7 +22,7 @@ import { findGitPath } from "./exec/locator.js";
|
|
|
22
22
|
* ```
|
|
23
23
|
*/
|
|
24
24
|
function createCliGitService(options) {
|
|
25
|
-
const service = GitService.createSingleton(options.watchingProvider);
|
|
25
|
+
const service = GitService.createSingleton(options.watchingProvider, { watchPolling: options.watchPolling });
|
|
26
26
|
const locator = options.locator ?? (() => findGitPath(options.gitPath ?? null));
|
|
27
27
|
const provider = new CliGitProvider({
|
|
28
28
|
context: options.context,
|
|
@@ -32,7 +32,10 @@ function createCliGitService(options) {
|
|
|
32
32
|
});
|
|
33
33
|
service.register(provider, () => true);
|
|
34
34
|
service.watchService?.onDidChangeWorkingTree((repoPath) => provider.cache.onWorkingTreeChanged(repoPath));
|
|
35
|
-
service.watchService?.onDidChangeRepository((e) =>
|
|
35
|
+
service.watchService?.onDidChangeRepository((e) => {
|
|
36
|
+
const changes = e.getUnannouncedChanges();
|
|
37
|
+
if (changes.length) provider.cache.onRepositoryChanged(e.repoPath, changes);
|
|
38
|
+
});
|
|
36
39
|
service.watchService?.onDidChangeFetchHead((repoPath) => provider.cache.onRepositoryChanged(repoPath, ["lastFetched"]));
|
|
37
40
|
return service;
|
|
38
41
|
}
|
|
@@ -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 { 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/**\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\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\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});\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\tservice.watchService?.onDidChangeRepository(e =>
|
|
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 { 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/**\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\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, { watchPolling: options.watchPolling });\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});\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":";;;;;;;;;;;;;;;;;;;;;;;AAkEA,SAAgB,oBAAoB,SAA2C;CAC9E,MAAM,UAAU,WAAW,gBAAgB,QAAQ,kBAAkB,EAAE,cAAc,QAAQ,aAAa,CAAC;CAE3G,MAAM,UAAU,QAAQ,kBAAkB,YAAY,QAAQ,WAAW,IAAI;CAC7E,MAAM,WAAW,IAAI,eAAe;EACnC,SAAS,QAAQ;EACR;EACT,YAAY,QAAQ;EACpB,OAAO,QAAQ;CAChB,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"}
|
package/dist/ipc/discovery.js
CHANGED
|
@@ -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
|