@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
|
@@ -8,8 +8,8 @@ import { joinPaths } from "../../utils/path.js";
|
|
|
8
8
|
import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
|
|
9
9
|
import { maxGitCliLength } from "../exec/git.js";
|
|
10
10
|
import * as l10n from "@vscode/l10n";
|
|
11
|
-
import { promises } from "fs";
|
|
12
11
|
import { tmpdir } from "os";
|
|
12
|
+
import { promises } from "fs";
|
|
13
13
|
//#region ../git-cli/src/providers/staging.ts
|
|
14
14
|
var StagingGitSubProvider = class {
|
|
15
15
|
context;
|
|
@@ -71,8 +71,12 @@ var StagingGitSubProvider = class {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
async stageFile(repoPath, pathOrUri) {
|
|
74
|
-
|
|
75
|
-
|
|
74
|
+
const path = toFsPath(pathOrUri);
|
|
75
|
+
try {
|
|
76
|
+
await this.git.run({ cwd: repoPath }, "add", "-A", "--", path);
|
|
77
|
+
} finally {
|
|
78
|
+
this.announceIndexChanged(repoPath);
|
|
79
|
+
}
|
|
76
80
|
}
|
|
77
81
|
async stageFiles(repoPath, pathsOrUris, options) {
|
|
78
82
|
const paths = pathsOrUris.map(toFsPath);
|
|
@@ -90,12 +94,20 @@ var StagingGitSubProvider = class {
|
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
async stageDirectory(repoPath, directoryOrUri) {
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
const path = toFsPath(directoryOrUri);
|
|
98
|
+
try {
|
|
99
|
+
await this.git.run({ cwd: repoPath }, "add", "-A", "--", path);
|
|
100
|
+
} finally {
|
|
101
|
+
this.announceIndexChanged(repoPath);
|
|
102
|
+
}
|
|
95
103
|
}
|
|
96
104
|
async unstageFile(repoPath, pathOrUri) {
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
const path = toFsPath(pathOrUri);
|
|
106
|
+
try {
|
|
107
|
+
await this.git.run({ cwd: repoPath }, "reset", "-q", "--", path);
|
|
108
|
+
} finally {
|
|
109
|
+
this.announceIndexChanged(repoPath);
|
|
110
|
+
}
|
|
99
111
|
}
|
|
100
112
|
async unstageFiles(repoPath, pathsOrUris) {
|
|
101
113
|
const paths = pathsOrUris.map(toFsPath);
|
|
@@ -110,15 +122,22 @@ var StagingGitSubProvider = class {
|
|
|
110
122
|
}
|
|
111
123
|
}
|
|
112
124
|
async unstageDirectory(repoPath, directoryOrUri) {
|
|
113
|
-
|
|
114
|
-
|
|
125
|
+
const path = toFsPath(directoryOrUri);
|
|
126
|
+
try {
|
|
127
|
+
await this.git.run({ cwd: repoPath }, "reset", "-q", "--", path);
|
|
128
|
+
} finally {
|
|
129
|
+
this.announceIndexChanged(repoPath);
|
|
130
|
+
}
|
|
115
131
|
}
|
|
116
132
|
async removeFile(repoPath, pathOrUri, options) {
|
|
117
133
|
const args = ["rm"];
|
|
118
134
|
if (options?.force) args.push("-f");
|
|
119
135
|
args.push("--", toFsPath(pathOrUri));
|
|
120
|
-
|
|
121
|
-
|
|
136
|
+
try {
|
|
137
|
+
await this.git.run({ cwd: repoPath }, ...args);
|
|
138
|
+
} finally {
|
|
139
|
+
this.announceIndexChanged(repoPath);
|
|
140
|
+
}
|
|
122
141
|
}
|
|
123
142
|
async removeFiles(repoPath, pathsOrUris, options) {
|
|
124
143
|
const paths = pathsOrUris.map(toFsPath);
|
|
@@ -136,12 +155,18 @@ var StagingGitSubProvider = class {
|
|
|
136
155
|
}
|
|
137
156
|
}
|
|
138
157
|
async stageAll(repoPath) {
|
|
139
|
-
|
|
140
|
-
|
|
158
|
+
try {
|
|
159
|
+
await this.git.run({ cwd: repoPath }, "add", "-A");
|
|
160
|
+
} finally {
|
|
161
|
+
this.announceIndexChanged(repoPath);
|
|
162
|
+
}
|
|
141
163
|
}
|
|
142
164
|
async unstageAll(repoPath) {
|
|
143
|
-
|
|
144
|
-
|
|
165
|
+
try {
|
|
166
|
+
await this.git.run({ cwd: repoPath }, "reset", "-q");
|
|
167
|
+
} finally {
|
|
168
|
+
this.announceIndexChanged(repoPath);
|
|
169
|
+
}
|
|
145
170
|
}
|
|
146
171
|
async clean(repoPath, options, runOptions) {
|
|
147
172
|
const args = ["clean"];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staging.js","names":["fs"],"sources":["../../../../git-cli/src/providers/staging.ts"],"sourcesContent":["import { promises as fs } from 'fs';\nimport { tmpdir } from 'os';\nimport * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '@gitlens/git/providers/staging.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { mixinAsyncDisposable } from '@gitlens/utils/disposable.js';\nimport { chunk } from '@gitlens/utils/iterable.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { joinPaths } from '@gitlens/utils/path.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { Git } from '../exec/git.js';\nimport { maxGitCliLength } from '../exec/git.js';\n\nexport class StagingGitSubProvider implements GitStagingSubProvider {\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 createTemporaryIndex(\n\t\trepoPath: string,\n\t\tfrom: 'empty' | 'current' | 'ref',\n\t\tref?: string,\n\t): Promise<DisposableTemporaryGitIndex> {\n\t\tconst scope = getScopedLogger();\n\n\t\t// Create a temporary index file\n\t\tconst tempDir = await fs.mkdtemp(joinPaths(tmpdir(), 'gl-'));\n\t\tconst tempIndex = joinPaths(tempDir, 'index');\n\n\t\tasync function dispose() {\n\t\t\t// Delete the temporary index file\n\t\t\ttry {\n\t\t\t\tawait fs.rm(tempDir, { recursive: true });\n\t\t\t} catch {\n\t\t\t\t// ignore cleanup errors\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Tell Git to use our soon to be created index file\n\t\t\tconst env = { GIT_INDEX_FILE: tempIndex };\n\n\t\t\tswitch (from) {\n\t\t\t\tcase 'empty':\n\t\t\t\t\t// Leave the temp index empty\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'current': {\n\t\t\t\t\t// Copy the current index to preserve staged state\n\t\t\t\t\tconst gitDir = await this.provider.config.getGitDir?.(repoPath);\n\t\t\t\t\tif (gitDir == null) throw new Error(l10n.t('Unable to determine git directory for {0}', repoPath));\n\n\t\t\t\t\tconst currentIndex = joinPaths(gitDir.uri.fsPath, 'index');\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait fs.copyFile(currentIndex, tempIndex);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t// A repo that has never staged anything has no index file yet; git reads a missing\n\t\t\t\t\t\t// `GIT_INDEX_FILE` as an empty index, which is what 'current' means there. Any other\n\t\t\t\t\t\t// failure is real — don't silently hand back an index claiming everything is deleted.\n\t\t\t\t\t\tif ((ex as NodeJS.ErrnoException)?.code !== 'ENOENT') throw ex;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'ref': {\n\t\t\t\t\tif (ref == null) throw new Error(l10n.t(\"ref is required when from is 'ref'\"));\n\n\t\t\t\t\t// Create the temp index file from a base ref/sha\n\t\t\t\t\tconst newIndexResult = await this.git.run(\n\t\t\t\t\t\t{ cwd: repoPath, env: env },\n\t\t\t\t\t\t'ls-tree',\n\t\t\t\t\t\t'-z',\n\t\t\t\t\t\t'-r',\n\t\t\t\t\t\t'--full-name',\n\t\t\t\t\t\tref,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (newIndexResult.stdout.trim()) {\n\t\t\t\t\t\t// Write the tree to our temp index\n\t\t\t\t\t\tawait this.git.run(\n\t\t\t\t\t\t\t{ cwd: repoPath, env: env, stdin: newIndexResult.stdout },\n\t\t\t\t\t\t\t'update-index',\n\t\t\t\t\t\t\t'-z',\n\t\t\t\t\t\t\t'--index-info',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn mixinAsyncDisposable({ path: tempIndex, env: { GIT_INDEX_FILE: tempIndex } }, dispose);\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\n\t\t\tvoid dispose();\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageFile(repoPath: string, pathOrUri: string | Uri): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A', '--', toFsPath(pathOrUri));\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync stageFiles(\n\t\trepoPath: string,\n\t\tpathsOrUris: (string | Uri)[],\n\t\toptions?: { intentToAdd?: boolean; index?: DisposableTemporaryGitIndex },\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run(\n\t\t\t\t\t{ cwd: repoPath, env: options?.index?.env },\n\t\t\t\t\t'add',\n\t\t\t\t\toptions?.intentToAdd ? '-N' : '-A',\n\t\t\t\t\t'--',\n\t\t\t\t\t...batch,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Announced even when a later batch fails, since the earlier ones already changed the index. A\n\t\t\t// temporary index (used for partial-stage previews / diff building) is not the repository's real\n\t\t\t// index — firing repo-change hooks for it would invalidate status caches for a mutation nothing\n\t\t\t// else can observe.\n\t\t\tif (options?.index == null) {\n\t\t\t\tthis.announceIndexChanged(repoPath);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A', '--', toFsPath(directoryOrUri));\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync unstageFile(repoPath: string, pathOrUri: string | Uri): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', toFsPath(pathOrUri));\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync unstageFiles(repoPath: string, pathsOrUris: (string | Uri)[]): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already changed the index\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unstageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', toFsPath(directoryOrUri));\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync removeFile(repoPath: string, pathOrUri: string | Uri, options?: { force?: boolean }): Promise<void> {\n\t\tconst args = ['rm'];\n\t\tif (options?.force) {\n\t\t\targs.push('-f');\n\t\t}\n\t\targs.push('--', toFsPath(pathOrUri));\n\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync removeFiles(repoPath: string, pathsOrUris: (string | Uri)[], options?: { force?: boolean }): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\tconst args: string[] = ['rm'];\n\t\tif (options?.force) {\n\t\t\targs.push('-f');\n\t\t}\n\t\targs.push('--');\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath }, ...args, ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already changed the index\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageAll(repoPath: string): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A');\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync unstageAll(repoPath: string): Promise<void> {\n\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q');\n\t\tthis.announceIndexChanged(repoPath);\n\t}\n\n\t@debug()\n\tasync clean(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tpaths?: (string | Uri)[];\n\t\t\tdirectories?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tignored?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst args = ['clean'];\n\t\tif (options?.force ?? true) {\n\t\t\targs.push('-f');\n\t\t}\n\t\tif (options?.directories) {\n\t\t\targs.push('-d');\n\t\t}\n\t\tif (options?.ignored) {\n\t\t\targs.push('-x');\n\t\t}\n\n\t\tif (options?.paths == null) {\n\t\t\ttry {\n\t\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args);\n\t\t\t} finally {\n\t\t\t\t// A clean that failed or was cancelled partway may already have removed files\n\t\t\t\tthis.announceIndexChanged(repoPath);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst paths = options.paths.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process paths in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args, '--', ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already removed files\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t/** What every index or working-tree mutation announces, so cached status is re-read and hosts are told. */\n\tprivate announceIndexChanged(repoPath: string): void {\n\t\t// `diff` and `tracking` too, as a watcher-observed index change clears them: a file's working-vs-index\n\t\t// diff and whether it is tracked both change when it is staged, unstaged or removed\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'status', 'diff', 'tracking');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['index']);\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;AAmBA,IAAa,wBAAb,MAAoE;CAEjD;CACA;CACA;CACA;CAJlB,YACC,SACA,KACA,OACA,UACC;EAJgB,KAAA,UAAA;EACA,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;CACf;CAEH,MACM,qBACL,UACA,MACA,KACuC;EACvC,MAAM,QAAQ,gBAAgB;EAG9B,MAAM,UAAU,MAAMA,SAAG,QAAQ,UAAU,OAAO,GAAG,KAAK,CAAC;EAC3D,MAAM,YAAY,UAAU,SAAS,OAAO;EAE5C,eAAe,UAAU;GAExB,IAAI;IACH,MAAMA,SAAG,GAAG,SAAS,EAAE,WAAW,KAAK,CAAC;GACzC,QAAQ,CAER;EACD;EAEA,IAAI;GAEH,MAAM,MAAM,EAAE,gBAAgB,UAAU;GAExC,QAAQ,MAAR;IACC,KAAK,SAEJ;IACD,KAAK,WAAW;KAEf,MAAM,SAAS,MAAM,KAAK,SAAS,OAAO,YAAY,QAAQ;KAC9D,IAAI,UAAU,MAAM,MAAM,IAAI,MAAM,KAAK,EAAE,6CAA6C,QAAQ,CAAC;KAEjG,MAAM,eAAe,UAAU,OAAO,IAAI,QAAQ,OAAO;KACzD,IAAI;MACH,MAAMA,SAAG,SAAS,cAAc,SAAS;KAC1C,SAAS,IAAI;MAIZ,IAAK,IAA8B,SAAS,UAAU,MAAM;KAC7D;KACA;IACD;IACA,KAAK,OAAO;KACX,IAAI,OAAO,MAAM,MAAM,IAAI,MAAM,KAAK,EAAE,oCAAoC,CAAC;KAG7E,MAAM,iBAAiB,MAAM,KAAK,IAAI,IACrC;MAAE,KAAK;MAAe;KAAI,GAC1B,WACA,MACA,MACA,eACA,GACD;KAEA,IAAI,eAAe,OAAO,KAAK,GAE9B,MAAM,KAAK,IAAI,IACd;MAAE,KAAK;MAAe;MAAK,OAAO,eAAe;KAAO,GACxD,gBACA,MACA,cACD;KAGD;IACD;GACD;GAEA,OAAO,qBAAqB;IAAE,MAAM;IAAW,KAAK,EAAE,gBAAgB,UAAU;GAAE,GAAG,OAAO;EAC7F,SAAS,IAAI;GACZ,OAAO,MAAM,EAAE;GAEf,QAAa;GACb,MAAM;EACP;CACD;CAEA,MACM,UAAU,UAAkB,WAAwC;EACzE,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,OAAO,MAAM,MAAM,SAAS,SAAS,CAAC;EAC5E,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,WACL,UACA,aACA,SACgB;EAChB,MAAM,QAAQ,YAAY,IAAI,QAAQ;EACtC,IAAI,CAAC,MAAM,QAAQ;EAGnB,MAAM,gBAAgB,kBAAkB,KAAK,IAAI,MAAM;EACvD,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,kBAAkB,aAAa,CAAC;EAGzE,MAAM,UAAU,MAAM,OAAO,SAAS;EACtC,IAAI;GACH,KAAK,MAAM,SAAS,SACnB,MAAM,KAAK,IAAI,IACd;IAAE,KAAK;IAAU,KAAK,SAAS,OAAO;GAAI,GAC1C,OACA,SAAS,cAAc,OAAO,MAC9B,MACA,GAAG,KACJ;EAEF,UAAU;GAKT,IAAI,SAAS,SAAS,MACrB,KAAK,qBAAqB,QAAQ;EAEpC;CACD;CAEA,MACM,eAAe,UAAkB,gBAA6C;EACnF,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,OAAO,MAAM,MAAM,SAAS,cAAc,CAAC;EACjF,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,YAAY,UAAkB,WAAwC;EAC3E,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,MAAM,MAAM,SAAS,SAAS,CAAC;EAC9E,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,aAAa,UAAkB,aAA8C;EAClF,MAAM,QAAQ,YAAY,IAAI,QAAQ;EACtC,IAAI,CAAC,MAAM,QAAQ;EAGnB,MAAM,gBAAgB,kBAAkB,KAAK,IAAI,MAAM;EACvD,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,kBAAkB,aAAa,CAAC;EAGzE,MAAM,UAAU,MAAM,OAAO,SAAS;EACtC,IAAI;GACH,KAAK,MAAM,SAAS,SACnB,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,MAAM,MAAM,GAAG,KAAK;EAErE,UAAU;GAET,KAAK,qBAAqB,QAAQ;EACnC;CACD;CAEA,MACM,iBAAiB,UAAkB,gBAA6C;EACrF,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,MAAM,MAAM,SAAS,cAAc,CAAC;EACnF,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,WAAW,UAAkB,WAAyB,SAA8C;EACzG,MAAM,OAAO,CAAC,IAAI;EAClB,IAAI,SAAS,OACZ,KAAK,KAAK,IAAI;EAEf,KAAK,KAAK,MAAM,SAAS,SAAS,CAAC;EACnC,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,GAAG,IAAI;EAC7C,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,YAAY,UAAkB,aAA+B,SAA8C;EAChH,MAAM,QAAQ,YAAY,IAAI,QAAQ;EACtC,IAAI,CAAC,MAAM,QAAQ;EAEnB,MAAM,OAAiB,CAAC,IAAI;EAC5B,IAAI,SAAS,OACZ,KAAK,KAAK,IAAI;EAEf,KAAK,KAAK,IAAI;EAGd,MAAM,gBAAgB,kBAAkB,KAAK,IAAI,MAAM;EACvD,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,kBAAkB,aAAa,CAAC;EAGzE,MAAM,UAAU,MAAM,OAAO,SAAS;EACtC,IAAI;GACH,KAAK,MAAM,SAAS,SACnB,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,GAAG,MAAM,GAAG,KAAK;EAEzD,UAAU;GAET,KAAK,qBAAqB,QAAQ;EACnC;CACD;CAEA,MACM,SAAS,UAAiC;EAC/C,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,OAAO,IAAI;EACjD,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,WAAW,UAAiC;EACjD,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,IAAI;EACnD,KAAK,qBAAqB,QAAQ;CACnC;CAEA,MACM,MACL,UACA,SAMA,YACgB;EAChB,MAAM,OAAO,CAAC,OAAO;EACrB,IAAI,SAAS,SAAS,MACrB,KAAK,KAAK,IAAI;EAEf,IAAI,SAAS,aACZ,KAAK,KAAK,IAAI;EAEf,IAAI,SAAS,SACZ,KAAK,KAAK,IAAI;EAGf,IAAI,SAAS,SAAS,MAAM;GAC3B,IAAI;IACH,MAAM,KAAK,IAAI,IAAI;KAAE,KAAK;KAAU,QAAQ;KAAS,GAAG;IAAW,GAAG,GAAG,IAAI;GAC9E,UAAU;IAET,KAAK,qBAAqB,QAAQ;GACnC;GACA;EACD;EAEA,MAAM,QAAQ,QAAQ,MAAM,IAAI,QAAQ;EACxC,IAAI,CAAC,MAAM,QAAQ;EAGnB,MAAM,gBAAgB,kBAAkB,KAAK,IAAI,MAAM;EACvD,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,kBAAkB,aAAa,CAAC;EAGzE,MAAM,UAAU,MAAM,OAAO,SAAS;EACtC,IAAI;GACH,KAAK,MAAM,SAAS,SACnB,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,QAAQ;IAAS,GAAG;GAAW,GAAG,GAAG,MAAM,MAAM,GAAG,KAAK;EAE/F,UAAU;GAET,KAAK,qBAAqB,QAAQ;EACnC;CACD;;CAGA,qBAA6B,UAAwB;EAGpD,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,UAAU,QAAQ,UAAU;EAC3E,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;CAChE;AACD;AA9QE,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,wBAAA,IAAA;AAiFN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,aAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,cAAA,IAAA;AAoCN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,kBAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,eAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,gBAAA,IAAA;AAqBN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,oBAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,cAAA,IAAA;AAWN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,eAAA,IAAA;AA2BN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,YAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,cAAA,IAAA;AAMN,WAAA,CAAA,MAAM,CAAA,GAAA,sBAAA,WAAA,SAAA,IAAA"}
|
|
1
|
+
{"version":3,"file":"staging.js","names":["fs"],"sources":["../../../../git-cli/src/providers/staging.ts"],"sourcesContent":["import { promises as fs } from 'fs';\nimport { tmpdir } from 'os';\nimport * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { DisposableTemporaryGitIndex, GitStagingSubProvider } from '@gitlens/git/providers/staging.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { mixinAsyncDisposable } from '@gitlens/utils/disposable.js';\nimport { chunk } from '@gitlens/utils/iterable.js';\nimport { getScopedLogger } from '@gitlens/utils/logger.scoped.js';\nimport { joinPaths } from '@gitlens/utils/path.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport type { Git } from '../exec/git.js';\nimport { maxGitCliLength } from '../exec/git.js';\n\nexport class StagingGitSubProvider implements GitStagingSubProvider {\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 createTemporaryIndex(\n\t\trepoPath: string,\n\t\tfrom: 'empty' | 'current' | 'ref',\n\t\tref?: string,\n\t): Promise<DisposableTemporaryGitIndex> {\n\t\tconst scope = getScopedLogger();\n\n\t\t// Create a temporary index file\n\t\tconst tempDir = await fs.mkdtemp(joinPaths(tmpdir(), 'gl-'));\n\t\tconst tempIndex = joinPaths(tempDir, 'index');\n\n\t\tasync function dispose() {\n\t\t\t// Delete the temporary index file\n\t\t\ttry {\n\t\t\t\tawait fs.rm(tempDir, { recursive: true });\n\t\t\t} catch {\n\t\t\t\t// ignore cleanup errors\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t// Tell Git to use our soon to be created index file\n\t\t\tconst env = { GIT_INDEX_FILE: tempIndex };\n\n\t\t\tswitch (from) {\n\t\t\t\tcase 'empty':\n\t\t\t\t\t// Leave the temp index empty\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'current': {\n\t\t\t\t\t// Copy the current index to preserve staged state\n\t\t\t\t\tconst gitDir = await this.provider.config.getGitDir?.(repoPath);\n\t\t\t\t\tif (gitDir == null) throw new Error(l10n.t('Unable to determine git directory for {0}', repoPath));\n\n\t\t\t\t\tconst currentIndex = joinPaths(gitDir.uri.fsPath, 'index');\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait fs.copyFile(currentIndex, tempIndex);\n\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t// A repo that has never staged anything has no index file yet; git reads a missing\n\t\t\t\t\t\t// `GIT_INDEX_FILE` as an empty index, which is what 'current' means there. Any other\n\t\t\t\t\t\t// failure is real — don't silently hand back an index claiming everything is deleted.\n\t\t\t\t\t\tif ((ex as NodeJS.ErrnoException)?.code !== 'ENOENT') throw ex;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'ref': {\n\t\t\t\t\tif (ref == null) throw new Error(l10n.t(\"ref is required when from is 'ref'\"));\n\n\t\t\t\t\t// Create the temp index file from a base ref/sha\n\t\t\t\t\tconst newIndexResult = await this.git.run(\n\t\t\t\t\t\t{ cwd: repoPath, env: env },\n\t\t\t\t\t\t'ls-tree',\n\t\t\t\t\t\t'-z',\n\t\t\t\t\t\t'-r',\n\t\t\t\t\t\t'--full-name',\n\t\t\t\t\t\tref,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (newIndexResult.stdout.trim()) {\n\t\t\t\t\t\t// Write the tree to our temp index\n\t\t\t\t\t\tawait this.git.run(\n\t\t\t\t\t\t\t{ cwd: repoPath, env: env, stdin: newIndexResult.stdout },\n\t\t\t\t\t\t\t'update-index',\n\t\t\t\t\t\t\t'-z',\n\t\t\t\t\t\t\t'--index-info',\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn mixinAsyncDisposable({ path: tempIndex, env: { GIT_INDEX_FILE: tempIndex } }, dispose);\n\t\t} catch (ex) {\n\t\t\tscope?.error(ex);\n\n\t\t\tvoid dispose();\n\t\t\tthrow ex;\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageFile(repoPath: string, pathOrUri: string | Uri): Promise<void> {\n\t\tconst path = toFsPath(pathOrUri);\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A', '--', path);\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageFiles(\n\t\trepoPath: string,\n\t\tpathsOrUris: (string | Uri)[],\n\t\toptions?: { intentToAdd?: boolean; index?: DisposableTemporaryGitIndex },\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run(\n\t\t\t\t\t{ cwd: repoPath, env: options?.index?.env },\n\t\t\t\t\t'add',\n\t\t\t\t\toptions?.intentToAdd ? '-N' : '-A',\n\t\t\t\t\t'--',\n\t\t\t\t\t...batch,\n\t\t\t\t);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Announced even when a later batch fails, since the earlier ones already changed the index. A\n\t\t\t// temporary index (used for partial-stage previews / diff building) is not the repository's real\n\t\t\t// index — firing repo-change hooks for it would invalidate status caches for a mutation nothing\n\t\t\t// else can observe.\n\t\t\tif (options?.index == null) {\n\t\t\t\tthis.announceIndexChanged(repoPath);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise<void> {\n\t\tconst path = toFsPath(directoryOrUri);\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A', '--', path);\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unstageFile(repoPath: string, pathOrUri: string | Uri): Promise<void> {\n\t\tconst path = toFsPath(pathOrUri);\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', path);\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unstageFiles(repoPath: string, pathsOrUris: (string | Uri)[]): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already changed the index\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unstageDirectory(repoPath: string, directoryOrUri: string | Uri): Promise<void> {\n\t\tconst path = toFsPath(directoryOrUri);\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q', '--', path);\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync removeFile(repoPath: string, pathOrUri: string | Uri, options?: { force?: boolean }): Promise<void> {\n\t\tconst args = ['rm'];\n\t\tif (options?.force) {\n\t\t\targs.push('-f');\n\t\t}\n\t\targs.push('--', toFsPath(pathOrUri));\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, ...args);\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync removeFiles(repoPath: string, pathsOrUris: (string | Uri)[], options?: { force?: boolean }): Promise<void> {\n\t\tconst paths = pathsOrUris.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\tconst args: string[] = ['rm'];\n\t\tif (options?.force) {\n\t\t\targs.push('-f');\n\t\t}\n\t\targs.push('--');\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process files in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath }, ...args, ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already changed the index\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync stageAll(repoPath: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'add', '-A');\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync unstageAll(repoPath: string): Promise<void> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'reset', '-q');\n\t\t} finally {\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug()\n\tasync clean(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tpaths?: (string | Uri)[];\n\t\t\tdirectories?: boolean;\n\t\t\tforce?: boolean;\n\t\t\tignored?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst args = ['clean'];\n\t\tif (options?.force ?? true) {\n\t\t\targs.push('-f');\n\t\t}\n\t\tif (options?.directories) {\n\t\t\targs.push('-d');\n\t\t}\n\t\tif (options?.ignored) {\n\t\t\targs.push('-x');\n\t\t}\n\n\t\tif (options?.paths == null) {\n\t\t\ttry {\n\t\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args);\n\t\t\t} finally {\n\t\t\t\t// A clean that failed or was cancelled partway may already have removed files\n\t\t\t\tthis.announceIndexChanged(repoPath);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tconst paths = options.paths.map(toFsPath);\n\t\tif (!paths.length) return;\n\n\t\t// Calculate a safe batch size based on average path length\n\t\tconst avgPathLength = countStringLength(paths) / paths.length;\n\t\tconst batchSize = Math.max(1, Math.floor(maxGitCliLength / avgPathLength));\n\n\t\t// Process paths in batches (will be a single batch if under the limit)\n\t\tconst batches = chunk(paths, batchSize);\n\t\ttry {\n\t\t\tfor (const batch of batches) {\n\t\t\t\tawait this.git.run({ cwd: repoPath, errors: 'throw', ...runOptions }, ...args, '--', ...batch);\n\t\t\t}\n\t\t} finally {\n\t\t\t// Even when a later batch fails, the earlier ones already removed files\n\t\t\tthis.announceIndexChanged(repoPath);\n\t\t}\n\t}\n\n\t/** What every index or working-tree mutation announces, so cached status is re-read and hosts are told. */\n\tprivate announceIndexChanged(repoPath: string): void {\n\t\t// `diff` and `tracking` too, as a watcher-observed index change clears them: a file's working-vs-index\n\t\t// diff and whether it is tracked both change when it is staged, unstaged or removed\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'status', 'diff', 'tracking');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['index']);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -32,6 +32,7 @@ export declare class StashGitSubProvider implements GitStashSubProvider {
|
|
|
32
32
|
private getStashCommitFilesCore;
|
|
33
33
|
deleteStash(repoPath: string, stashName: string, sha?: string): Promise<void>;
|
|
34
34
|
private deleteStashCore;
|
|
35
|
+
private verifyStashSha;
|
|
35
36
|
renameStash(repoPath: string, stashName: string, sha: string, message: string, stashOnRef?: string): Promise<void>;
|
|
36
37
|
saveStash(repoPath: string, message?: string, pathsOrUris?: (string | Uri)[], options?: {
|
|
37
38
|
includeUntracked?: boolean;
|
|
@@ -40,6 +41,7 @@ export declare class StashGitSubProvider implements GitStashSubProvider {
|
|
|
40
41
|
}, runOptions?: GitOperationRunOptions): Promise<void>;
|
|
41
42
|
private stashPushCore;
|
|
42
43
|
saveSnapshot(repoPath: string, message?: string): Promise<void>;
|
|
44
|
+
private announceStashChanged;
|
|
43
45
|
}
|
|
44
46
|
export declare function convertStashesToStdin(stashOrStashes: GitStash | ReadonlyMap<string, GitStashCommit> | undefined): {
|
|
45
47
|
readonly stdin: string | undefined;
|
|
@@ -142,28 +142,37 @@ var StashGitSubProvider = class {
|
|
|
142
142
|
} : void 0, void 0, void 0, f.mode)) ?? [];
|
|
143
143
|
}
|
|
144
144
|
async deleteStash(repoPath, stashName, sha) {
|
|
145
|
-
await this.deleteStashCore(repoPath, stashName, sha);
|
|
146
|
-
this.context.hooks?.repository?.onChanged?.(repoPath, ["stash"]);
|
|
147
|
-
this.context.hooks?.cache?.onReset?.(repoPath, "stashes");
|
|
145
|
+
await this.deleteStashCore(repoPath, stashName, sha, { announce: true });
|
|
148
146
|
}
|
|
149
|
-
async deleteStashCore(repoPath, stashName, sha) {
|
|
147
|
+
async deleteStashCore(repoPath, stashName, sha, options) {
|
|
150
148
|
if (!stashName) return void 0;
|
|
149
|
+
if (!options.verified) await this.verifyStashSha(repoPath, stashName, sha);
|
|
151
150
|
let result;
|
|
152
|
-
|
|
153
|
-
result = await this.git.run({
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
}, "show", "--format=%H", "--no-patch", stashName);
|
|
157
|
-
if (result.stdout.trim() !== sha) throw new Error(l10n.t("Unable to delete stash; mismatch with stash number"));
|
|
151
|
+
try {
|
|
152
|
+
result = await this.git.run({ cwd: repoPath }, "stash", "drop", stashName);
|
|
153
|
+
} finally {
|
|
154
|
+
if (options.announce) this.announceStashChanged(repoPath);
|
|
158
155
|
}
|
|
159
|
-
result = await this.git.run({ cwd: repoPath }, "stash", "drop", stashName);
|
|
160
156
|
return result.stdout;
|
|
161
157
|
}
|
|
158
|
+
async verifyStashSha(repoPath, stashName, sha) {
|
|
159
|
+
if (!sha) return;
|
|
160
|
+
if ((await this.git.run({
|
|
161
|
+
cwd: repoPath,
|
|
162
|
+
errors: "ignore"
|
|
163
|
+
}, "show", "--format=%H", "--no-patch", stashName)).stdout.trim() !== sha) throw new Error(l10n.t("Unable to delete stash; mismatch with stash number"));
|
|
164
|
+
}
|
|
162
165
|
async renameStash(repoPath, stashName, sha, message, stashOnRef) {
|
|
163
|
-
await this.
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
166
|
+
if (stashName) await this.verifyStashSha(repoPath, stashName, sha);
|
|
167
|
+
try {
|
|
168
|
+
await this.deleteStashCore(repoPath, stashName, sha, {
|
|
169
|
+
announce: false,
|
|
170
|
+
verified: true
|
|
171
|
+
});
|
|
172
|
+
await this.git.run({ cwd: repoPath }, "stash", "store", "-m", stashOnRef ? `On ${stashOnRef}: ${message}` : message, sha);
|
|
173
|
+
} finally {
|
|
174
|
+
this.announceStashChanged(repoPath);
|
|
175
|
+
}
|
|
167
176
|
}
|
|
168
177
|
async saveStash(repoPath, message, pathsOrUris, options, runOptions) {
|
|
169
178
|
const paths = pathsOrUris?.map(toFsPath);
|
|
@@ -236,9 +245,15 @@ var StashGitSubProvider = class {
|
|
|
236
245
|
if (id == null) return;
|
|
237
246
|
const args = [];
|
|
238
247
|
if (message) args.push("-m", message);
|
|
239
|
-
|
|
240
|
-
|
|
248
|
+
try {
|
|
249
|
+
await this.git.run({ cwd: repoPath }, "stash", "store", ...args, id);
|
|
250
|
+
} finally {
|
|
251
|
+
this.announceStashChanged(repoPath);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
announceStashChanged(repoPath) {
|
|
241
255
|
this.context.hooks?.cache?.onReset?.(repoPath, "stashes");
|
|
256
|
+
this.context.hooks?.repository?.onChanged?.(repoPath, ["stash"]);
|
|
242
257
|
}
|
|
243
258
|
};
|
|
244
259
|
__decorate([gate(), debug()], StashGitSubProvider.prototype, "applyStash", null);
|
|
@@ -246,7 +261,7 @@ __decorate([debug()], StashGitSubProvider.prototype, "createStash", null);
|
|
|
246
261
|
__decorate([debug()], StashGitSubProvider.prototype, "getStash", null);
|
|
247
262
|
__decorate([debug()], StashGitSubProvider.prototype, "getStashCommitFiles", null);
|
|
248
263
|
__decorate([debug()], StashGitSubProvider.prototype, "deleteStash", null);
|
|
249
|
-
__decorate([gate()], StashGitSubProvider.prototype, "deleteStashCore", null);
|
|
264
|
+
__decorate([gate((rp, name, sha) => `${rp}\0${name}\0${sha ?? ""}`)], StashGitSubProvider.prototype, "deleteStashCore", null);
|
|
250
265
|
__decorate([debug()], StashGitSubProvider.prototype, "renameStash", null);
|
|
251
266
|
__decorate([debug({ args: (repoPath, message, paths) => ({
|
|
252
267
|
repoPath,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stash.js","names":[],"sources":["../../../../git-cli/src/providers/stash.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { StashApplyError, StashPushError } from '@gitlens/git/errors.js';\nimport type { GitStashCommit } from '@gitlens/git/models/commit.js';\nimport { GitCommit, GitCommitIdentity } from '@gitlens/git/models/commit.js';\nimport { GitFileChange } from '@gitlens/git/models/fileChange.js';\nimport type { GitFileStatus } from '@gitlens/git/models/fileStatus.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitStash } from '@gitlens/git/models/stash.js';\nimport type { GitUser } from '@gitlens/git/models/user.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitStashSubProvider, StashApplyResult } from '@gitlens/git/providers/stash.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { skip } from '@gitlens/utils/iterable.js';\nimport { normalizePath, splitPath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, joinUriPath, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { gitFeaturesByVersion } from '../exec/features.js';\nimport type { Git } from '../exec/git.js';\nimport { getGitCommandError, GitError, GitErrors, maxGitCliLength } from '../exec/git.js';\nimport type { ParsedStash, ParsedStashWithFiles } from '../parsers/logParser.js';\nimport { getStashFilesOnlyLogParser, getStashLogParser } from '../parsers/logParser.js';\nimport { createCommitFileset } from './commitFilesetUtils.js';\n\nexport class StashGitSubProvider implements GitStashSubProvider {\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t) {}\n\n\t@gate()\n\t@debug()\n\tasync applyStash(\n\t\trepoPath: string,\n\t\tstashNameOrSha: string,\n\t\toptions?: { deleteAfter?: boolean; index?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\tif (!stashNameOrSha) return { conflicted: false };\n\n\t\tconst args = ['stash', options?.deleteAfter ? 'pop' : 'apply'];\n\t\tif (options?.index) {\n\t\t\targs.push('--index');\n\t\t}\n\t\targs.push(stashNameOrSha);\n\t\treturn this.applyStashCore(repoPath, args, options?.deleteAfter ? 'stash-pop' : 'stash-apply', runOptions);\n\t}\n\n\tprivate async applyStashCore(\n\t\trepoPath: string,\n\t\targs: string[],\n\t\tconflictCommand: 'stash-apply' | 'stash-pop',\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\t\t\treturn { conflicted: false };\n\t\t} catch (ex) {\n\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tconst msg: string = ex.message ?? '';\n\t\t\t\tif (\n\t\t\t\t\t(msg.includes('Auto-merging') && msg.includes('CONFLICT')) ||\n\t\t\t\t\t(ex instanceof GitError &&\n\t\t\t\t\t\t((ex.stdout?.includes('Auto-merging') && ex.stdout.includes('CONFLICT')) ||\n\t\t\t\t\t\t\tex.stdout?.includes('needs merge')))\n\t\t\t\t) {\n\t\t\t\t\tthis.context.hooks?.operations?.onConflicted?.(conflictCommand);\n\t\t\t\t\treturn { conflicted: true };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-apply',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashApplyError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A conflicted, failed or cancelled apply may already have changed the stash list or working tree\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync createStash(repoPath: string, message?: string): Promise<string | undefined> {\n\t\tconst args = ['stash', 'create'];\n\t\tif (message) {\n\t\t\targs.push(message);\n\t\t}\n\n\t\tconst result = await this.git.run({ cwd: repoPath }, ...args);\n\t\treturn result.stdout.trim() || undefined;\n\t}\n\n\t@debug()\n\tasync getStash(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tincludeFiles?: boolean;\n\t\t\treachableFrom?: string;\n\t\t\tsimilarityThreshold?: number | null;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStash | undefined> {\n\t\tif (repoPath == null) return undefined;\n\n\t\t// Resolve options against config up front so the cache key reflects the actual values used\n\t\t// to produce the cached payload — undefined inputs aren't conflated across config changes.\n\t\tconst cfg = this.context.config;\n\t\tconst includeFiles = options?.includeFiles ?? cfg?.commits.includeFileDetails?.(repoPath) ?? true;\n\t\tconst similarityThreshold = includeFiles\n\t\t\t? (options?.similarityThreshold ?? cfg?.commits.similarityThreshold ?? null)\n\t\t\t: null;\n\t\tconst reachableFrom = options?.reachableFrom;\n\n\t\t// Cache only the unfiltered stash list; reachability projection runs below by testing each\n\t\t// distinct stash parent against `reachableFrom` directly, so re-projecting is cheap\n\t\tconst cacheKey = `f${includeFiles ? 1 : 0}|s${similarityThreshold ?? ''}`;\n\n\t\tconst stash = await this.cache.getStash(\n\t\t\trepoPath,\n\t\t\tcacheKey,\n\t\t\tasync (commonPath, _cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst parser = getStashLogParser(includeFiles);\n\t\t\t\tconst args = [...parser.arguments];\n\n\t\t\t\tif (includeFiles) {\n\t\t\t\t\targs.push(`-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`);\n\t\t\t\t}\n\n\t\t\t\tconst result = await this.git.run({ cwd: repoPath, cancellation: signal }, 'stash', 'list', ...args);\n\n\t\t\t\tconst currentUser = await this.provider.config.getCurrentUser(repoPath);\n\n\t\t\t\tconst stashes = new Map<string, GitStashCommit>();\n\t\t\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\t\t\tstashes.set(s.sha, createStash(s, commonPath, currentUser));\n\t\t\t\t}\n\n\t\t\t\treturn { repoPath: commonPath, stashes: stashes };\n\t\t\t},\n\t\t\t{ cancellation: cancellation },\n\t\t);\n\n\t\tif (stash == null || !reachableFrom || !stash.stashes.size) return stash;\n\n\t\t// Copy because the cached `stash.stashes` map is shared and must not be mutated.\n\t\tconst stashes = new Map(stash.stashes);\n\n\t\tconst reachableStashes = new Set<string>();\n\n\t\t// Metadata pass: a stash belongs on `reachableFrom` iff git's auto-prepended\n\t\t// `On <branch>: …` (or `WIP on <branch>: …`) prefix in the stash commit subject names\n\t\t// this branch. `stashOnRef` is parsed from %s in createStash, so this covers autostashes\n\t\t// and custom-reflog stashes too.\n\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\tif (s.stashOnRef === reachableFrom) {\n\t\t\t\treachableStashes.add(sha);\n\t\t\t}\n\t\t}\n\n\t\t// Transitive pass for the rare detached-HEAD-on-stash chain (stash B created while HEAD\n\t\t// pointed at stash A). Such stashes have no `stashOnRef`, but if their parent is a stash\n\t\t// already marked reachable they should follow.\n\t\tlet changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\t\tif (!reachableStashes.has(sha) && s.parents.some(p => reachableStashes.has(p))) {\n\t\t\t\t\treachableStashes.add(sha);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (changed);\n\n\t\tfor (const [sha] of stash.stashes) {\n\t\t\tif (!reachableStashes.has(sha)) {\n\t\t\t\tstashes.delete(sha);\n\t\t\t}\n\t\t}\n\n\t\treturn { ...stash, stashes: stashes };\n\t}\n\n\t@debug()\n\tasync getStashCommitFiles(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[]> {\n\t\tconst [stashFilesResult, stashUntrackedFilesResult] = await Promise.allSettled([\n\t\t\t// Don't include untracked files here, because we won't be able to tell them apart from added (and we need the untracked status)\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: false, ...options }, cancellation),\n\t\t\t// Check for any untracked files -- since git doesn't return them via `git stash list` :(\n\t\t\t// See https://stackoverflow.com/questions/12681529/\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: 'only', ...options }, cancellation),\n\t\t]);\n\n\t\tlet files = getSettledValue(stashFilesResult);\n\t\tconst untrackedFiles = getSettledValue(stashUntrackedFilesResult);\n\n\t\tif (files?.length && untrackedFiles?.length) {\n\t\t\tfiles.push(...untrackedFiles);\n\t\t} else {\n\t\t\tfiles = files ?? untrackedFiles;\n\t\t}\n\n\t\treturn files ?? [];\n\t}\n\n\tprivate async getStashCommitFilesCore(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null; untracked?: boolean | 'only' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[] | undefined> {\n\t\tconst args = [];\n\t\tif (options?.untracked) {\n\t\t\targs.push(options?.untracked === 'only' ? '--only-untracked' : '--include-untracked');\n\t\t}\n\n\t\tconst similarityThreshold = options?.similarityThreshold ?? this.context.config?.commits.similarityThreshold;\n\t\tif (similarityThreshold != null) {\n\t\t\targs.push(`-M${similarityThreshold}%`);\n\t\t}\n\n\t\tconst parser = getStashFilesOnlyLogParser();\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'stash',\n\t\t\t'show',\n\t\t\t...args,\n\t\t\t...parser.arguments,\n\t\t\tref,\n\t\t);\n\n\t\tconst repoUri = fileUri(normalizePath(repoPath));\n\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\treturn (\n\t\t\t\ts.files?.map(\n\t\t\t\t\tf =>\n\t\t\t\t\t\tnew GitFileChange(\n\t\t\t\t\t\t\trepoPath,\n\t\t\t\t\t\t\tf.path,\n\t\t\t\t\t\t\t(options?.untracked === 'only'\n\t\t\t\t\t\t\t\t? GitFileWorkingTreeStatus.Untracked\n\t\t\t\t\t\t\t\t: f.status) as GitFileStatus,\n\t\t\t\t\t\t\tjoinUriPath(repoUri, normalizePath(f.path)),\n\t\t\t\t\t\t\tf.originalPath,\n\t\t\t\t\t\t\tf.originalPath != null ? joinUriPath(repoUri, normalizePath(f.originalPath)) : undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.additions || f.deletions\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tadditions: f.additions ?? 0,\n\t\t\t\t\t\t\t\t\t\tdeletions: f.deletions ?? 0,\n\t\t\t\t\t\t\t\t\t\tchanges: 0,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.mode,\n\t\t\t\t\t\t),\n\t\t\t\t) ?? []\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t@debug()\n\tasync deleteStash(repoPath: string, stashName: string, sha?: string): Promise<void> {\n\t\tawait this.deleteStashCore(repoPath, stashName, sha);\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t}\n\n\t@gate()\n\tprivate async deleteStashCore(repoPath: string, stashName: string, sha?: string): Promise<string | undefined> {\n\t\tif (!stashName) return undefined;\n\n\t\tlet result;\n\t\tif (sha) {\n\t\t\tresult = await this.git.run(\n\t\t\t\t{ cwd: repoPath, errors: 'ignore' },\n\t\t\t\t'show',\n\t\t\t\t'--format=%H',\n\t\t\t\t'--no-patch',\n\t\t\t\tstashName,\n\t\t\t);\n\t\t\tif (result.stdout.trim() !== sha) {\n\t\t\t\tthrow new Error(l10n.t('Unable to delete stash; mismatch with stash number'));\n\t\t\t}\n\t\t}\n\n\t\tresult = await this.git.run({ cwd: repoPath }, 'stash', 'drop', stashName);\n\t\treturn result.stdout;\n\t}\n\n\t@debug()\n\tasync renameStash(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string,\n\t\tmessage: string,\n\t\tstashOnRef?: string,\n\t): Promise<void> {\n\t\tawait this.deleteStashCore(repoPath, stashName, sha);\n\t\tawait this.git.run(\n\t\t\t{ cwd: repoPath },\n\t\t\t'stash',\n\t\t\t'store',\n\t\t\t'-m',\n\t\t\tstashOnRef ? `On ${stashOnRef}: ${message}` : message,\n\t\t\tsha,\n\t\t);\n\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t}\n\n\t@debug({ args: (repoPath, message, paths) => ({ repoPath: repoPath, message: message, paths: paths?.length }) })\n\tasync saveStash(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\tpathsOrUris?: (string | Uri)[],\n\t\toptions?: { includeUntracked?: boolean; keepIndex?: boolean; onlyStaged?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris?.map(toFsPath);\n\t\tif (!paths?.length) {\n\t\t\tawait this.stashPushCore(repoPath, message, options, runOptions);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.git.ensureSupports('git:stash:push:pathspecs', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Stashing individual files requires a newer version of Git (>= {0}) than is currently installed ({1}). Please retry by stashing everything or install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathspecs = paths.map(p => `./${splitPath(p, repoPath)[0]}`);\n\n\t\tlet stdin = await this.git.supports('git:stash:push:stdin');\n\t\tif (stdin && options?.onlyStaged && paths.length) {\n\t\t\t// Since Git doesn't support --staged with --pathspec-from-file try to pass them in directly\n\t\t\tstdin = false;\n\t\t}\n\n\t\t// If we don't support stdin, then error out if we are over the maximum allowed git cli length\n\t\tif (!stdin && countStringLength(pathspecs) > maxGitCliLength) {\n\t\t\tawait this.git.ensureSupports('git:stash:push:stdin', (requiredVersion, installedVersion) =>\n\t\t\t\tl10n.t(\n\t\t\t\t\t'Stashing so many files ({0}) at once requires a newer version of Git (>= {1}) than is currently installed ({2}). Please retry by stashing fewer files or install a more recent version of Git and try again.',\n\t\t\t\t\tpathspecs.length,\n\t\t\t\t\trequiredVersion,\n\t\t\t\t\tinstalledVersion,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait this.stashPushCore(\n\t\t\trepoPath,\n\t\t\tmessage,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tpathspecs: pathspecs,\n\t\t\t\tstdin: stdin,\n\t\t\t},\n\t\t\trunOptions,\n\t\t);\n\t}\n\n\tprivate async stashPushCore(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\toptions?: {\n\t\t\tincludeUntracked?: boolean;\n\t\t\tkeepIndex?: boolean;\n\t\t\tonlyStaged?: boolean;\n\t\t\tpathspecs?: string[];\n\t\t\tstdin?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst params = ['stash', 'push'];\n\n\t\tif ((options?.includeUntracked || options?.pathspecs?.length) && !options?.onlyStaged) {\n\t\t\tparams.push('--include-untracked');\n\t\t}\n\n\t\t// `git stash push --keep-index --include-untracked -- <pathspec>` hits a bug in git when the\n\t\t// pathspec names an untracked file: the restoring checkout can't match an untracked path in the\n\t\t// index tree, so it fails and the staged changes are lost.\n\t\t//\n\t\t// $ mkdir stash-test && cd stash-test && git init\n\t\t// $ echo a > a.txt\n\t\t// $ git add a.txt\n\t\t// $ git commit -m init\n\t\t// $ echo b > b.txt\n\t\t// $ git stash push --keep-index --include-untracked -- b.txt\n\t\t// Saved working directory and index state WIP on main: 8a280fe init\n\t\t// error: pathspec ':(prefix:0)b.txt' did not match any file(s) known to git\n\t\t//\n\t\t// Only suppress --keep-index for that case — when the selection actually includes untracked\n\t\t// files (`includeUntracked`) AND we're stashing by pathspec. Keying off `includeUntracked` (the\n\t\t// caller's intent) rather than the `--include-untracked` flag is deliberate: we add\n\t\t// `--include-untracked` to every pathspec push above as a safety net, but a tracked-only\n\t\t// selection can — and must — still keep the index intact.\n\t\tif (options?.keepIndex && !(options?.includeUntracked && options?.pathspecs?.length)) {\n\t\t\tparams.push('--keep-index');\n\t\t}\n\n\t\tif (options?.onlyStaged) {\n\t\t\tif (await this.git.supports('git:stash:push:staged')) {\n\t\t\t\tparams.push('--staged');\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tl10n.t(\n\t\t\t\t\t\t'Git version {0} or higher is required for --staged',\n\t\t\t\t\t\tString(gitFeaturesByVersion.get('git:stash:push:staged')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (message) {\n\t\t\tparams.push('-m', message);\n\t\t}\n\n\t\tlet stdin;\n\t\tif (options?.pathspecs?.length) {\n\t\t\tif (options.stdin) {\n\t\t\t\tstdin = options.pathspecs.join('\\0');\n\t\t\t\tparams.push('--pathspec-from-file=-', '--pathspec-file-nul', '--');\n\t\t\t} else {\n\t\t\t\tparams.push('--', ...options.pathspecs);\n\t\t\t}\n\t\t} else {\n\t\t\tparams.push('--');\n\t\t}\n\n\t\tlet nothingToSave = false;\n\t\ttry {\n\t\t\tconst result = await this.git.run({ cwd: repoPath, ...runOptions, stdin: stdin }, ...params);\n\t\t\tif (GitErrors.stashNothingToSave.test(result.stdout)) {\n\t\t\t\tnothingToSave = true;\n\t\t\t\tthrow new StashPushError({\n\t\t\t\t\treason: 'nothingToSave',\n\t\t\t\t\tgitCommand: { repoPath: repoPath, args: params },\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof StashPushError || isCancellationError(ex)) throw ex;\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-push',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashPushError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: params } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled push may already have stashed, and reset the working tree; one with nothing to\n\t\t\t// save changed nothing\n\t\t\tif (!nothingToSave) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync saveSnapshot(repoPath: string, message?: string): Promise<void> {\n\t\tconst result = await this.git.run({ cwd: repoPath }, 'stash', 'create');\n\t\tconst id = result.stdout.trim() || undefined;\n\t\tif (id == null) return;\n\n\t\tconst args = [];\n\t\tif (message) {\n\t\t\targs.push('-m', message);\n\t\t}\n\t\tawait this.git.run({ cwd: repoPath }, 'stash', 'store', ...args, id);\n\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t}\n}\n\nexport function convertStashesToStdin(stashOrStashes: GitStash | ReadonlyMap<string, GitStashCommit> | undefined): {\n\treadonly stdin: string | undefined;\n\treadonly stashes: Map<string, GitStashCommit>;\n\treadonly remappedIds: Map<string, string>;\n} {\n\tconst remappedIds = new Map<string, string>();\n\tif (stashOrStashes == null) return { stdin: undefined, stashes: new Map(), remappedIds: remappedIds };\n\n\tlet stdin: string | undefined;\n\tconst original = 'stashes' in stashOrStashes ? stashOrStashes.stashes : stashOrStashes;\n\tconst stashes = new Map<string, GitStashCommit>(original);\n\n\tif (original.size) {\n\t\tstdin = '';\n\t\tfor (const stash of original.values()) {\n\t\t\tstdin += `${stash.sha.substring(0, 9)}\\n`;\n\t\t\t// Include the stash's 2nd (index files) and 3rd (untracked files) parents (if they aren't already in the map)\n\t\t\tfor (const p of skip(stash.parents, 1)) {\n\t\t\t\tremappedIds.set(p, stash.sha);\n\n\t\t\t\tif (!stashes.has(p)) {\n\t\t\t\t\tstashes.set(p, stash);\n\t\t\t\t\tstdin += `${p.substring(0, 9)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { stdin: stdin || undefined, stashes: stashes, remappedIds: remappedIds };\n}\n\nconst stashSummaryRegex =\n\t// oxlint-disable-next-line no-control-regex\n\t/(?:(?:(?<wip>WIP) on|On) (?<onref>[^/](?!.*\\/\\.)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*@\\{)[^\\x00-\\x1F\\x7F ~^:?*[\\\\]+[^./]):\\s*)?(?<summary>.*)$/s;\n\nfunction createStash(\n\ts: ParsedStash | ParsedStashWithFiles,\n\trepoPath: string,\n\tcurrentUser: GitUser | undefined,\n): GitStashCommit {\n\t// `onRef` comes from the commit subject (%s), which git always prefixes with `On <branch>: …`\n\t// or `WIP on <branch>: …`. This holds even when the reflog message was customized\n\t// (autostash, `git stash store -m \"…\"`), so it's a reliable source\n\tlet onRef: string | undefined;\n\tconst subjectMatch = stashSummaryRegex.exec((s.commitSubject ?? '').trim());\n\tif (subjectMatch?.groups?.onref) {\n\t\tonRef = subjectMatch.groups.onref;\n\t}\n\n\t// The user-visible display message is derived from the reflog subject (%gs) so that short\n\t// custom messages like \"wip\", \"q\", or \"show args\" stay as the user wrote them instead of\n\t// being replaced by the verbose git-auto subject\n\tlet message = s.summary.trim();\n\tconst reflogMatch = stashSummaryRegex.exec(message);\n\tif (reflogMatch?.groups != null) {\n\t\tconst summary = reflogMatch.groups.summary.trim();\n\t\tif (summary.length === 0) {\n\t\t\tmessage = 'WIP';\n\t\t} else if (reflogMatch.groups.wip) {\n\t\t\tmessage = `WIP: ${summary}`;\n\t\t} else {\n\t\t\tmessage = summary;\n\t\t}\n\t}\n\n\tconst index = message.indexOf('\\n');\n\n\treturn new GitCommit(\n\t\trepoPath,\n\t\ts.sha,\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.authorDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.committedDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tindex !== -1 ? message.substring(0, index) : message,\n\t\ts.parents.split(' ') ?? [],\n\t\tmessage,\n\t\tcreateCommitFileset(s, repoPath, undefined),\n\t\ts.stats,\n\t\tundefined,\n\t\tundefined,\n\t\ts.stashName,\n\t\tonRef,\n\t) as GitStashCommit;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA8BA,IAAa,sBAAb,MAAgE;CAE7C;CACA;CACA;CACA;CAJlB,YACC,SACA,KACA,OACA,UACC;EAJgB,KAAA,UAAA;EACA,KAAA,MAAA;EACA,KAAA,QAAA;EACA,KAAA,WAAA;CACf;CAEH,MAEM,WACL,UACA,gBACA,SACA,YAC4B;EAC5B,IAAI,CAAC,gBAAgB,OAAO,EAAE,YAAY,MAAM;EAEhD,MAAM,OAAO,CAAC,SAAS,SAAS,cAAc,QAAQ,OAAO;EAC7D,IAAI,SAAS,OACZ,KAAK,KAAK,SAAS;EAEpB,KAAK,KAAK,cAAc;EACxB,OAAO,KAAK,eAAe,UAAU,MAAM,SAAS,cAAc,cAAc,eAAe,UAAU;CAC1G;CAEA,MAAc,eACb,UACA,MACA,iBACA,YAC4B;EAC5B,IAAI;GACH,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,GAAG;GAAW,GAAG,GAAG,IAAI;GAC5D,OAAO,EAAE,YAAY,MAAM;EAC5B,SAAS,IAAI;GACZ,IAAI,oBAAoB,EAAE,GAAG,MAAM;GAEnC,IAAI,cAAc,OAAO;IACxB,MAAM,MAAc,GAAG,WAAW;IAClC,IACE,IAAI,SAAS,cAAc,KAAK,IAAI,SAAS,UAAU,KACvD,cAAc,aACZ,GAAG,QAAQ,SAAS,cAAc,KAAK,GAAG,OAAO,SAAS,UAAU,KACrE,GAAG,QAAQ,SAAS,aAAa,IAClC;KACD,KAAK,QAAQ,OAAO,YAAY,eAAe,eAAe;KAC9D,OAAO,EAAE,YAAY,KAAK;IAC3B;GACD;GAEA,MAAM,mBACL,eACA,KACA,WACC,IAAI,gBACH;IAAE,QAAQ,UAAU;IAAS,YAAY;KAAY;KAAgB;IAAK;GAAE,GAC5E,EACD,CACF;EACD,UAAU;GAET,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW,QAAQ;GAClE,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;EAChE;CACD;CAEA,MACM,YAAY,UAAkB,SAA+C;EAClF,MAAM,OAAO,CAAC,SAAS,QAAQ;EAC/B,IAAI,SACH,KAAK,KAAK,OAAO;EAIlB,QAAO,MADc,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,GAAG,IAAI,EAAA,CAC9C,OAAO,KAAK,KAAK,KAAA;CAChC;CAEA,MACM,SACL,UACA,SAKA,cACgC;EAChC,IAAI,YAAY,MAAM,OAAO,KAAA;EAI7B,MAAM,MAAM,KAAK,QAAQ;EACzB,MAAM,eAAe,SAAS,gBAAgB,KAAK,QAAQ,qBAAqB,QAAQ,KAAK;EAC7F,MAAM,sBAAsB,eACxB,SAAS,uBAAuB,KAAK,QAAQ,uBAAuB,OACrE;EACH,MAAM,gBAAgB,SAAS;EAI/B,MAAM,WAAW,IAAI,eAAe,IAAI,EAAE,IAAI,uBAAuB;EAErE,MAAM,QAAQ,MAAM,KAAK,MAAM,SAC9B,UACA,UACA,OAAO,YAAY,YAAY,WAAW;GAEzC,WAAW;GACX,MAAM,SAAS,kBAAkB,YAAY;GAC7C,MAAM,OAAO,CAAC,GAAG,OAAO,SAAS;GAEjC,IAAI,cACH,KAAK,KAAK,KAAK,uBAAuB,OAAO,KAAK,GAAG,oBAAoB,IAAI;GAG9E,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,cAAc;GAAO,GAAG,SAAS,QAAQ,GAAG,IAAI;GAEnG,MAAM,cAAc,MAAM,KAAK,SAAS,OAAO,eAAe,QAAQ;GAEtE,MAAM,0BAAU,IAAI,IAA4B;GAChD,KAAK,MAAM,KAAK,OAAO,MAAM,OAAO,MAAM,GACzC,QAAQ,IAAI,EAAE,KAAK,YAAY,GAAG,YAAY,WAAW,CAAC;GAG3D,OAAO;IAAE,UAAU;IAAqB;GAAQ;EACjD,GACA,EAAgB,aAAa,CAC9B;EAEA,IAAI,SAAS,QAAQ,CAAC,iBAAiB,CAAC,MAAM,QAAQ,MAAM,OAAO;EAGnE,MAAM,UAAU,IAAI,IAAI,MAAM,OAAO;EAErC,MAAM,mCAAmB,IAAI,IAAY;EAMzC,KAAK,MAAM,CAAC,KAAK,MAAM,MAAM,SAC5B,IAAI,EAAE,eAAe,eACpB,iBAAiB,IAAI,GAAG;EAO1B,IAAI;EACJ,GAAG;GACF,UAAU;GACV,KAAK,MAAM,CAAC,KAAK,MAAM,MAAM,SAC5B,IAAI,CAAC,iBAAiB,IAAI,GAAG,KAAK,EAAE,QAAQ,MAAK,MAAK,iBAAiB,IAAI,CAAC,CAAC,GAAG;IAC/E,iBAAiB,IAAI,GAAG;IACxB,UAAU;GACX;EAEF,SAAS;EAET,KAAK,MAAM,CAAC,QAAQ,MAAM,SACzB,IAAI,CAAC,iBAAiB,IAAI,GAAG,GAC5B,QAAQ,OAAO,GAAG;EAIpB,OAAO;GAAE,GAAG;GAAgB;EAAQ;CACrC;CAEA,MACM,oBACL,UACA,KACA,SACA,cAC2B;EAC3B,MAAM,CAAC,kBAAkB,6BAA6B,MAAM,QAAQ,WAAW,CAE9E,KAAK,wBAAwB,UAAU,KAAK;GAAE,WAAW;GAAO,GAAG;EAAQ,GAAG,YAAY,GAG1F,KAAK,wBAAwB,UAAU,KAAK;GAAE,WAAW;GAAQ,GAAG;EAAQ,GAAG,YAAY,CAC5F,CAAC;EAED,IAAI,QAAQ,gBAAgB,gBAAgB;EAC5C,MAAM,iBAAiB,gBAAgB,yBAAyB;EAEhE,IAAI,OAAO,UAAU,gBAAgB,QACpC,MAAM,KAAK,GAAG,cAAc;OAE5B,QAAQ,SAAS;EAGlB,OAAO,SAAS,CAAC;CAClB;CAEA,MAAc,wBACb,UACA,KACA,SACA,cACuC;EACvC,MAAM,OAAO,CAAC;EACd,IAAI,SAAS,WACZ,KAAK,KAAK,SAAS,cAAc,SAAS,qBAAqB,qBAAqB;EAGrF,MAAM,sBAAsB,SAAS,uBAAuB,KAAK,QAAQ,QAAQ,QAAQ;EACzF,IAAI,uBAAuB,MAC1B,KAAK,KAAK,KAAK,oBAAoB,EAAE;EAGtC,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,MAAM,KAAK,IAAI,IAC7B;GAAE,KAAK;GAAwB;EAAa,GAC5C,SACA,QACA,GAAG,MACH,GAAG,OAAO,WACV,GACD;EAEA,MAAM,UAAU,QAAQ,cAAc,QAAQ,CAAC;EAC/C,KAAK,MAAM,KAAK,OAAO,MAAM,OAAO,MAAM,GACzC,OACC,EAAE,OAAO,KACR,MACC,IAAI,cACH,UACA,EAAE,MACD,SAAS,cAAc,SACrB,yBAAyB,YACzB,EAAE,QACL,YAAY,SAAS,cAAc,EAAE,IAAI,CAAC,GAC1C,EAAE,cACF,EAAE,gBAAgB,OAAO,YAAY,SAAS,cAAc,EAAE,YAAY,CAAC,IAAI,KAAA,GAC/E,KAAA,GACA,EAAE,aAAa,EAAE,YACd;GACA,WAAW,EAAE,aAAa;GAC1B,WAAW,EAAE,aAAa;GAC1B,SAAS;EACV,IACC,KAAA,GACH,KAAA,GACA,KAAA,GACA,EAAE,IACH,CACF,KAAK,CAAC;CAKT;CAEA,MACM,YAAY,UAAkB,WAAmB,KAA6B;EACnF,MAAM,KAAK,gBAAgB,UAAU,WAAW,GAAG;EACnD,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;EAC/D,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,SAAS;CACzD;CAEA,MACc,gBAAgB,UAAkB,WAAmB,KAA2C;EAC7G,IAAI,CAAC,WAAW,OAAO,KAAA;EAEvB,IAAI;EACJ,IAAI,KAAK;GACR,SAAS,MAAM,KAAK,IAAI,IACvB;IAAE,KAAK;IAAU,QAAQ;GAAS,GAClC,QACA,eACA,cACA,SACD;GACA,IAAI,OAAO,OAAO,KAAK,MAAM,KAC5B,MAAM,IAAI,MAAM,KAAK,EAAE,oDAAoD,CAAC;EAE9E;EAEA,SAAS,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,QAAQ,SAAS;EACzE,OAAO,OAAO;CACf;CAEA,MACM,YACL,UACA,WACA,KACA,SACA,YACgB;EAChB,MAAM,KAAK,gBAAgB,UAAU,WAAW,GAAG;EACnD,MAAM,KAAK,IAAI,IACd,EAAE,KAAK,SAAS,GAChB,SACA,SACA,MACA,aAAa,MAAM,WAAW,IAAI,YAAY,SAC9C,GACD;EAEA,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;EAC/D,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,SAAS;CACzD;CAEA,MACM,UACL,UACA,SACA,aACA,SACA,YACgB;EAChB,MAAM,QAAQ,aAAa,IAAI,QAAQ;EACvC,IAAI,CAAC,OAAO,QAAQ;GACnB,MAAM,KAAK,cAAc,UAAU,SAAS,SAAS,UAAU;GAC/D;EACD;EAEA,MAAM,KAAK,IAAI,eAAe,6BAA6B,iBAAiB,qBAC3E,KAAK,EACJ,oMACA,iBACA,gBACD,CACD;EAEA,MAAM,YAAY,MAAM,KAAI,MAAK,KAAK,UAAU,GAAG,QAAQ,CAAC,CAAC,IAAI;EAEjE,IAAI,QAAQ,MAAM,KAAK,IAAI,SAAS,sBAAsB;EAC1D,IAAI,SAAS,SAAS,cAAc,MAAM,QAEzC,QAAQ;EAIT,IAAI,CAAC,SAAS,kBAAkB,SAAS,IAAA,KACxC,MAAM,KAAK,IAAI,eAAe,yBAAyB,iBAAiB,qBACvE,KAAK,EACJ,gNACA,UAAU,QACV,iBACA,gBACD,CACD;EAGD,MAAM,KAAK,cACV,UACA,SACA;GACC,GAAG;GACQ;GACJ;EACR,GACA,UACD;CACD;CAEA,MAAc,cACb,UACA,SACA,SAOA,YACgB;EAChB,MAAM,SAAS,CAAC,SAAS,MAAM;EAE/B,KAAK,SAAS,oBAAoB,SAAS,WAAW,WAAW,CAAC,SAAS,YAC1E,OAAO,KAAK,qBAAqB;EAqBlC,IAAI,SAAS,aAAa,EAAE,SAAS,oBAAoB,SAAS,WAAW,SAC5E,OAAO,KAAK,cAAc;EAG3B,IAAI,SAAS,YAAY;GACxB,IAAI,MAAM,KAAK,IAAI,SAAS,uBAAuB,GAClD,OAAO,KAAK,UAAU;QAEtB,MAAM,IAAI,MACT,KAAK,EACJ,sDACA,OAAO,qBAAqB,IAAI,uBAAuB,CAAC,CACzD,CACD;EAEF;EAEA,IAAI,SACH,OAAO,KAAK,MAAM,OAAO;EAG1B,IAAI;EACJ,IAAI,SAAS,WAAW,QAAQ;GAC/B,IAAI,QAAQ,OAAO;IAClB,QAAQ,QAAQ,UAAU,KAAK,IAAI;IACnC,OAAO,KAAK,0BAA0B,uBAAuB,IAAI;GAClE,OACC,OAAO,KAAK,MAAM,GAAG,QAAQ,SAAS;EAExC,OACC,OAAO,KAAK,IAAI;EAGjB,IAAI,gBAAgB;EACpB,IAAI;GACH,MAAM,SAAS,MAAM,KAAK,IAAI,IAAI;IAAE,KAAK;IAAU,GAAG;IAAmB;GAAM,GAAG,GAAG,MAAM;GAC3F,IAAI,UAAU,mBAAmB,KAAK,OAAO,MAAM,GAAG;IACrD,gBAAgB;IAChB,MAAM,IAAI,eAAe;KACxB,QAAQ;KACR,YAAY;MAAY;MAAU,MAAM;KAAO;IAChD,CAAC;GACF;EACD,SAAS,IAAI;GACZ,IAAI,cAAc,kBAAkB,oBAAoB,EAAE,GAAG,MAAM;GAEnE,MAAM,mBACL,cACA,KACA,WACC,IAAI,eACH;IAAE,QAAQ,UAAU;IAAS,YAAY;KAAY;KAAU,MAAM;IAAO;GAAE,GAC9E,EACD,CACF;EACD,UAAU;GAGT,IAAI,CAAC,eAAe;IACnB,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,WAAW,QAAQ;IAClE,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;GAChE;EACD;CACD;CAEA,MACM,aAAa,UAAkB,SAAiC;EAErE,MAAM,MAAK,MADU,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,QAAQ,EAAA,CACpD,OAAO,KAAK,KAAK,KAAA;EACnC,IAAI,MAAM,MAAM;EAEhB,MAAM,OAAO,CAAC;EACd,IAAI,SACH,KAAK,KAAK,MAAM,OAAO;EAExB,MAAM,KAAK,IAAI,IAAI,EAAE,KAAK,SAAS,GAAG,SAAS,SAAS,GAAG,MAAM,EAAE;EAEnE,KAAK,QAAQ,OAAO,YAAY,YAAY,UAAU,CAAC,OAAO,CAAC;EAC/D,KAAK,QAAQ,OAAO,OAAO,UAAU,UAAU,SAAS;CACzD;AACD;AArdE,WAAA,CAAA,KAAK,GACL,MAAM,CAAA,GAAA,oBAAA,WAAA,cAAA,IAAA;AA0DN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,eAAA,IAAA;AAWN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,YAAA,IAAA;AA4FN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,uBAAA,IAAA;AAsFN,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,eAAA,IAAA;AAON,WAAA,CAAA,KAAK,CAAA,GAAA,oBAAA,WAAA,mBAAA,IAAA;AAsBL,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,eAAA,IAAA;AAsBN,WAAA,CAAA,MAAM,EAAE,OAAO,UAAU,SAAS,WAAW;CAAY;CAAmB;CAAS,OAAO,OAAO;AAAO,GAAG,CAAC,CAAA,GAAA,oBAAA,WAAA,aAAA,IAAA;AA2J9G,WAAA,CAAA,MAAM,CAAA,GAAA,oBAAA,WAAA,gBAAA,IAAA;AAiBR,SAAgB,sBAAsB,gBAIpC;CACD,MAAM,8BAAc,IAAI,IAAoB;CAC5C,IAAI,kBAAkB,MAAM,OAAO;EAAE,OAAO,KAAA;EAAW,yBAAS,IAAI,IAAI;EAAgB;CAAY;CAEpG,IAAI;CACJ,MAAM,WAAW,aAAa,iBAAiB,eAAe,UAAU;CACxE,MAAM,UAAU,IAAI,IAA4B,QAAQ;CAExD,IAAI,SAAS,MAAM;EAClB,QAAQ;EACR,KAAK,MAAM,SAAS,SAAS,OAAO,GAAG;GACtC,SAAS,GAAG,MAAM,IAAI,UAAU,GAAG,CAAC,EAAE;GAEtC,KAAK,MAAM,KAAK,KAAK,MAAM,SAAS,CAAC,GAAG;IACvC,YAAY,IAAI,GAAG,MAAM,GAAG;IAE5B,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG;KACpB,QAAQ,IAAI,GAAG,KAAK;KACpB,SAAS,GAAG,EAAE,UAAU,GAAG,CAAC,EAAE;IAC/B;GACD;EACD;CACD;CAEA,OAAO;EAAE,OAAO,SAAS,KAAA;EAAoB;EAAsB;CAAY;AAChF;AAEA,MAAM,oBAEL;AAED,SAAS,YACR,GACA,UACA,aACiB;CAIjB,IAAI;CACJ,MAAM,eAAe,kBAAkB,MAAM,EAAE,iBAAiB,GAAA,CAAI,KAAK,CAAC;CAC1E,IAAI,cAAc,QAAQ,OACzB,QAAQ,aAAa,OAAO;CAM7B,IAAI,UAAU,EAAE,QAAQ,KAAK;CAC7B,MAAM,cAAc,kBAAkB,KAAK,OAAO;CAClD,IAAI,aAAa,UAAU,MAAM;EAChC,MAAM,UAAU,YAAY,OAAO,QAAQ,KAAK;EAChD,IAAI,QAAQ,WAAW,GACtB,UAAU;OACJ,IAAI,YAAY,OAAO,KAC7B,UAAU,QAAQ;OAElB,UAAU;CAEZ;CAEA,MAAM,QAAQ,QAAQ,QAAQ,IAAI;CAElC,OAAO,IAAI,UACV,UACA,EAAE,KACF,IAAI,kBACH,aAAa,QAAQ,IACrB,aAAa,uBACb,IAAI,KAAK,OAAO,EAAE,UAAU,IAAI,GAAI,GACpC,KAAA,GACA,IACD,GACA,IAAI,kBACH,aAAa,QAAQ,IACrB,aAAa,uBACb,IAAI,KAAK,OAAO,EAAE,aAAa,IAAI,GAAI,GACvC,KAAA,GACA,IACD,GACA,UAAU,KAAK,QAAQ,UAAU,GAAG,KAAK,IAAI,SAC7C,EAAE,QAAQ,MAAM,GAAG,KAAK,CAAC,GACzB,SACA,oBAAoB,GAAG,UAAU,KAAA,CAAS,GAC1C,EAAE,OACF,KAAA,GACA,KAAA,GACA,EAAE,WACF,KACD;AACD"}
|
|
1
|
+
{"version":3,"file":"stash.js","names":[],"sources":["../../../../git-cli/src/providers/stash.ts"],"sourcesContent":["import * as l10n from '@vscode/l10n';\nimport type { Cache } from '@gitlens/git/cache.js';\nimport type { GitServiceContext } from '@gitlens/git/context.js';\nimport { StashApplyError, StashPushError } from '@gitlens/git/errors.js';\nimport type { GitStashCommit } from '@gitlens/git/models/commit.js';\nimport { GitCommit, GitCommitIdentity } from '@gitlens/git/models/commit.js';\nimport { GitFileChange } from '@gitlens/git/models/fileChange.js';\nimport type { GitFileStatus } from '@gitlens/git/models/fileStatus.js';\nimport { GitFileWorkingTreeStatus } from '@gitlens/git/models/fileStatus.js';\nimport type { GitStash } from '@gitlens/git/models/stash.js';\nimport type { GitUser } from '@gitlens/git/models/user.js';\nimport type { GitOperationRunOptions } from '@gitlens/git/providers/operations.js';\nimport type { GitStashSubProvider, StashApplyResult } from '@gitlens/git/providers/stash.js';\nimport { countStringLength } from '@gitlens/utils/array.js';\nimport { isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { gate } from '@gitlens/utils/decorators/gate.js';\nimport { debug } from '@gitlens/utils/decorators/log.js';\nimport { skip } from '@gitlens/utils/iterable.js';\nimport { normalizePath, splitPath } from '@gitlens/utils/path.js';\nimport { getSettledValue } from '@gitlens/utils/promise.js';\nimport type { Uri } from '@gitlens/utils/uri.js';\nimport { fileUri, joinUriPath, toFsPath } from '@gitlens/utils/uri.js';\nimport type { CliGitProviderInternal } from '../cliGitProvider.js';\nimport { gitFeaturesByVersion } from '../exec/features.js';\nimport type { Git } from '../exec/git.js';\nimport { getGitCommandError, GitError, GitErrors, maxGitCliLength } from '../exec/git.js';\nimport type { ParsedStash, ParsedStashWithFiles } from '../parsers/logParser.js';\nimport { getStashFilesOnlyLogParser, getStashLogParser } from '../parsers/logParser.js';\nimport { createCommitFileset } from './commitFilesetUtils.js';\n\nexport class StashGitSubProvider implements GitStashSubProvider {\n\tconstructor(\n\t\tprivate readonly context: GitServiceContext,\n\t\tprivate readonly git: Git,\n\t\tprivate readonly cache: Cache,\n\t\tprivate readonly provider: CliGitProviderInternal,\n\t) {}\n\n\t@gate()\n\t@debug()\n\tasync applyStash(\n\t\trepoPath: string,\n\t\tstashNameOrSha: string,\n\t\toptions?: { deleteAfter?: boolean; index?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\tif (!stashNameOrSha) return { conflicted: false };\n\n\t\tconst args = ['stash', options?.deleteAfter ? 'pop' : 'apply'];\n\t\tif (options?.index) {\n\t\t\targs.push('--index');\n\t\t}\n\t\targs.push(stashNameOrSha);\n\t\treturn this.applyStashCore(repoPath, args, options?.deleteAfter ? 'stash-pop' : 'stash-apply', runOptions);\n\t}\n\n\tprivate async applyStashCore(\n\t\trepoPath: string,\n\t\targs: string[],\n\t\tconflictCommand: 'stash-apply' | 'stash-pop',\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<StashApplyResult> {\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath, ...runOptions }, ...args);\n\t\t\treturn { conflicted: false };\n\t\t} catch (ex) {\n\t\t\tif (isCancellationError(ex)) throw ex;\n\n\t\t\tif (ex instanceof Error) {\n\t\t\t\tconst msg: string = ex.message ?? '';\n\t\t\t\tif (\n\t\t\t\t\t(msg.includes('Auto-merging') && msg.includes('CONFLICT')) ||\n\t\t\t\t\t(ex instanceof GitError &&\n\t\t\t\t\t\t((ex.stdout?.includes('Auto-merging') && ex.stdout.includes('CONFLICT')) ||\n\t\t\t\t\t\t\tex.stdout?.includes('needs merge')))\n\t\t\t\t) {\n\t\t\t\t\tthis.context.hooks?.operations?.onConflicted?.(conflictCommand);\n\t\t\t\t\treturn { conflicted: true };\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-apply',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashApplyError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: args } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A conflicted, failed or cancelled apply may already have changed the stash list or working tree\n\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t}\n\t}\n\n\t@debug()\n\tasync createStash(repoPath: string, message?: string): Promise<string | undefined> {\n\t\tconst args = ['stash', 'create'];\n\t\tif (message) {\n\t\t\targs.push(message);\n\t\t}\n\n\t\tconst result = await this.git.run({ cwd: repoPath }, ...args);\n\t\treturn result.stdout.trim() || undefined;\n\t}\n\n\t@debug()\n\tasync getStash(\n\t\trepoPath: string,\n\t\toptions?: {\n\t\t\tincludeFiles?: boolean;\n\t\t\treachableFrom?: string;\n\t\t\tsimilarityThreshold?: number | null;\n\t\t},\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitStash | undefined> {\n\t\tif (repoPath == null) return undefined;\n\n\t\t// Resolve options against config up front so the cache key reflects the actual values used\n\t\t// to produce the cached payload — undefined inputs aren't conflated across config changes.\n\t\tconst cfg = this.context.config;\n\t\tconst includeFiles = options?.includeFiles ?? cfg?.commits.includeFileDetails?.(repoPath) ?? true;\n\t\tconst similarityThreshold = includeFiles\n\t\t\t? (options?.similarityThreshold ?? cfg?.commits.similarityThreshold ?? null)\n\t\t\t: null;\n\t\tconst reachableFrom = options?.reachableFrom;\n\n\t\t// Cache only the unfiltered stash list; reachability projection runs below by testing each\n\t\t// distinct stash parent against `reachableFrom` directly, so re-projecting is cheap\n\t\tconst cacheKey = `f${includeFiles ? 1 : 0}|s${similarityThreshold ?? ''}`;\n\n\t\tconst stash = await this.cache.getStash(\n\t\t\trepoPath,\n\t\t\tcacheKey,\n\t\t\tasync (commonPath, _cacheable, signal) => {\n\t\t\t\t// Prefer the aggregate signal from the cache; fall back to the caller's cancellation.\n\t\t\t\tsignal ??= cancellation;\n\t\t\t\tconst parser = getStashLogParser(includeFiles);\n\t\t\t\tconst args = [...parser.arguments];\n\n\t\t\t\tif (includeFiles) {\n\t\t\t\t\targs.push(`-M${similarityThreshold == null ? '' : `${similarityThreshold}%`}`);\n\t\t\t\t}\n\n\t\t\t\tconst result = await this.git.run({ cwd: repoPath, cancellation: signal }, 'stash', 'list', ...args);\n\n\t\t\t\tconst currentUser = await this.provider.config.getCurrentUser(repoPath);\n\n\t\t\t\tconst stashes = new Map<string, GitStashCommit>();\n\t\t\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\t\t\tstashes.set(s.sha, createStash(s, commonPath, currentUser));\n\t\t\t\t}\n\n\t\t\t\treturn { repoPath: commonPath, stashes: stashes };\n\t\t\t},\n\t\t\t{ cancellation: cancellation },\n\t\t);\n\n\t\tif (stash == null || !reachableFrom || !stash.stashes.size) return stash;\n\n\t\t// Copy because the cached `stash.stashes` map is shared and must not be mutated.\n\t\tconst stashes = new Map(stash.stashes);\n\n\t\tconst reachableStashes = new Set<string>();\n\n\t\t// Metadata pass: a stash belongs on `reachableFrom` iff git's auto-prepended\n\t\t// `On <branch>: …` (or `WIP on <branch>: …`) prefix in the stash commit subject names\n\t\t// this branch. `stashOnRef` is parsed from %s in createStash, so this covers autostashes\n\t\t// and custom-reflog stashes too.\n\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\tif (s.stashOnRef === reachableFrom) {\n\t\t\t\treachableStashes.add(sha);\n\t\t\t}\n\t\t}\n\n\t\t// Transitive pass for the rare detached-HEAD-on-stash chain (stash B created while HEAD\n\t\t// pointed at stash A). Such stashes have no `stashOnRef`, but if their parent is a stash\n\t\t// already marked reachable they should follow.\n\t\tlet changed;\n\t\tdo {\n\t\t\tchanged = false;\n\t\t\tfor (const [sha, s] of stash.stashes) {\n\t\t\t\tif (!reachableStashes.has(sha) && s.parents.some(p => reachableStashes.has(p))) {\n\t\t\t\t\treachableStashes.add(sha);\n\t\t\t\t\tchanged = true;\n\t\t\t\t}\n\t\t\t}\n\t\t} while (changed);\n\n\t\tfor (const [sha] of stash.stashes) {\n\t\t\tif (!reachableStashes.has(sha)) {\n\t\t\t\tstashes.delete(sha);\n\t\t\t}\n\t\t}\n\n\t\treturn { ...stash, stashes: stashes };\n\t}\n\n\t@debug()\n\tasync getStashCommitFiles(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[]> {\n\t\tconst [stashFilesResult, stashUntrackedFilesResult] = await Promise.allSettled([\n\t\t\t// Don't include untracked files here, because we won't be able to tell them apart from added (and we need the untracked status)\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: false, ...options }, cancellation),\n\t\t\t// Check for any untracked files -- since git doesn't return them via `git stash list` :(\n\t\t\t// See https://stackoverflow.com/questions/12681529/\n\t\t\tthis.getStashCommitFilesCore(repoPath, ref, { untracked: 'only', ...options }, cancellation),\n\t\t]);\n\n\t\tlet files = getSettledValue(stashFilesResult);\n\t\tconst untrackedFiles = getSettledValue(stashUntrackedFilesResult);\n\n\t\tif (files?.length && untrackedFiles?.length) {\n\t\t\tfiles.push(...untrackedFiles);\n\t\t} else {\n\t\t\tfiles = files ?? untrackedFiles;\n\t\t}\n\n\t\treturn files ?? [];\n\t}\n\n\tprivate async getStashCommitFilesCore(\n\t\trepoPath: string,\n\t\tref: string,\n\t\toptions?: { similarityThreshold?: number | null; untracked?: boolean | 'only' },\n\t\tcancellation?: AbortSignal,\n\t): Promise<GitFileChange[] | undefined> {\n\t\tconst args = [];\n\t\tif (options?.untracked) {\n\t\t\targs.push(options?.untracked === 'only' ? '--only-untracked' : '--include-untracked');\n\t\t}\n\n\t\tconst similarityThreshold = options?.similarityThreshold ?? this.context.config?.commits.similarityThreshold;\n\t\tif (similarityThreshold != null) {\n\t\t\targs.push(`-M${similarityThreshold}%`);\n\t\t}\n\n\t\tconst parser = getStashFilesOnlyLogParser();\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, cancellation: cancellation },\n\t\t\t'stash',\n\t\t\t'show',\n\t\t\t...args,\n\t\t\t...parser.arguments,\n\t\t\tref,\n\t\t);\n\n\t\tconst repoUri = fileUri(normalizePath(repoPath));\n\t\tfor (const s of parser.parse(result.stdout)) {\n\t\t\treturn (\n\t\t\t\ts.files?.map(\n\t\t\t\t\tf =>\n\t\t\t\t\t\tnew GitFileChange(\n\t\t\t\t\t\t\trepoPath,\n\t\t\t\t\t\t\tf.path,\n\t\t\t\t\t\t\t(options?.untracked === 'only'\n\t\t\t\t\t\t\t\t? GitFileWorkingTreeStatus.Untracked\n\t\t\t\t\t\t\t\t: f.status) as GitFileStatus,\n\t\t\t\t\t\t\tjoinUriPath(repoUri, normalizePath(f.path)),\n\t\t\t\t\t\t\tf.originalPath,\n\t\t\t\t\t\t\tf.originalPath != null ? joinUriPath(repoUri, normalizePath(f.originalPath)) : undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.additions || f.deletions\n\t\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\t\tadditions: f.additions ?? 0,\n\t\t\t\t\t\t\t\t\t\tdeletions: f.deletions ?? 0,\n\t\t\t\t\t\t\t\t\t\tchanges: 0,\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tundefined,\n\t\t\t\t\t\t\tf.mode,\n\t\t\t\t\t\t),\n\t\t\t\t) ?? []\n\t\t\t);\n\t\t}\n\n\t\treturn undefined;\n\t}\n\n\t@debug()\n\tasync deleteStash(repoPath: string, stashName: string, sha?: string): Promise<void> {\n\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: true });\n\t}\n\n\t// Keyed without `options`, so a delete and a rename of the same stash share one drop: a second drop would take\n\t// the stash that moved up into its place\n\t@gate((rp, name, sha) => `${rp}\\0${name}\\0${sha ?? ''}`)\n\tprivate async deleteStashCore(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string | undefined,\n\t\toptions: { announce: boolean; verified?: boolean },\n\t): Promise<string | undefined> {\n\t\tif (!stashName) return undefined;\n\n\t\tif (!options.verified) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\tlet result;\n\t\ttry {\n\t\t\tresult = await this.git.run({ cwd: repoPath }, 'stash', 'drop', stashName);\n\t\t} finally {\n\t\t\tif (options.announce) {\n\t\t\t\tthis.announceStashChanged(repoPath);\n\t\t\t}\n\t\t}\n\t\treturn result.stdout;\n\t}\n\n\tprivate async verifyStashSha(repoPath: string, stashName: string, sha: string | undefined): Promise<void> {\n\t\tif (!sha) return;\n\n\t\tconst result = await this.git.run(\n\t\t\t{ cwd: repoPath, errors: 'ignore' },\n\t\t\t'show',\n\t\t\t'--format=%H',\n\t\t\t'--no-patch',\n\t\t\tstashName,\n\t\t);\n\t\tif (result.stdout.trim() !== sha) {\n\t\t\tthrow new Error(l10n.t('Unable to delete stash; mismatch with stash number'));\n\t\t}\n\t}\n\n\t@debug()\n\tasync renameStash(\n\t\trepoPath: string,\n\t\tstashName: string,\n\t\tsha: string,\n\t\tmessage: string,\n\t\tstashOnRef?: string,\n\t): Promise<void> {\n\t\tif (stashName) {\n\t\t\tawait this.verifyStashSha(repoPath, stashName, sha);\n\t\t}\n\n\t\t// The drop and the store announce once, after both ran, even if the store fails\n\t\ttry {\n\t\t\tawait this.deleteStashCore(repoPath, stashName, sha, { announce: false, verified: true });\n\t\t\tawait this.git.run(\n\t\t\t\t{ cwd: repoPath },\n\t\t\t\t'stash',\n\t\t\t\t'store',\n\t\t\t\t'-m',\n\t\t\t\tstashOnRef ? `On ${stashOnRef}: ${message}` : message,\n\t\t\t\tsha,\n\t\t\t);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\t@debug({ args: (repoPath, message, paths) => ({ repoPath: repoPath, message: message, paths: paths?.length }) })\n\tasync saveStash(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\tpathsOrUris?: (string | Uri)[],\n\t\toptions?: { includeUntracked?: boolean; keepIndex?: boolean; onlyStaged?: boolean },\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst paths = pathsOrUris?.map(toFsPath);\n\t\tif (!paths?.length) {\n\t\t\tawait this.stashPushCore(repoPath, message, options, runOptions);\n\t\t\treturn;\n\t\t}\n\n\t\tawait this.git.ensureSupports('git:stash:push:pathspecs', (requiredVersion, installedVersion) =>\n\t\t\tl10n.t(\n\t\t\t\t'Stashing individual files requires a newer version of Git (>= {0}) than is currently installed ({1}). Please retry by stashing everything or install a more recent version of Git and try again.',\n\t\t\t\trequiredVersion,\n\t\t\t\tinstalledVersion,\n\t\t\t),\n\t\t);\n\n\t\tconst pathspecs = paths.map(p => `./${splitPath(p, repoPath)[0]}`);\n\n\t\tlet stdin = await this.git.supports('git:stash:push:stdin');\n\t\tif (stdin && options?.onlyStaged && paths.length) {\n\t\t\t// Since Git doesn't support --staged with --pathspec-from-file try to pass them in directly\n\t\t\tstdin = false;\n\t\t}\n\n\t\t// If we don't support stdin, then error out if we are over the maximum allowed git cli length\n\t\tif (!stdin && countStringLength(pathspecs) > maxGitCliLength) {\n\t\t\tawait this.git.ensureSupports('git:stash:push:stdin', (requiredVersion, installedVersion) =>\n\t\t\t\tl10n.t(\n\t\t\t\t\t'Stashing so many files ({0}) at once requires a newer version of Git (>= {1}) than is currently installed ({2}). Please retry by stashing fewer files or install a more recent version of Git and try again.',\n\t\t\t\t\tpathspecs.length,\n\t\t\t\t\trequiredVersion,\n\t\t\t\t\tinstalledVersion,\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\n\t\tawait this.stashPushCore(\n\t\t\trepoPath,\n\t\t\tmessage,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tpathspecs: pathspecs,\n\t\t\t\tstdin: stdin,\n\t\t\t},\n\t\t\trunOptions,\n\t\t);\n\t}\n\n\tprivate async stashPushCore(\n\t\trepoPath: string,\n\t\tmessage?: string,\n\t\toptions?: {\n\t\t\tincludeUntracked?: boolean;\n\t\t\tkeepIndex?: boolean;\n\t\t\tonlyStaged?: boolean;\n\t\t\tpathspecs?: string[];\n\t\t\tstdin?: boolean;\n\t\t},\n\t\trunOptions?: GitOperationRunOptions,\n\t): Promise<void> {\n\t\tconst params = ['stash', 'push'];\n\n\t\tif ((options?.includeUntracked || options?.pathspecs?.length) && !options?.onlyStaged) {\n\t\t\tparams.push('--include-untracked');\n\t\t}\n\n\t\t// `git stash push --keep-index --include-untracked -- <pathspec>` hits a bug in git when the\n\t\t// pathspec names an untracked file: the restoring checkout can't match an untracked path in the\n\t\t// index tree, so it fails and the staged changes are lost.\n\t\t//\n\t\t// $ mkdir stash-test && cd stash-test && git init\n\t\t// $ echo a > a.txt\n\t\t// $ git add a.txt\n\t\t// $ git commit -m init\n\t\t// $ echo b > b.txt\n\t\t// $ git stash push --keep-index --include-untracked -- b.txt\n\t\t// Saved working directory and index state WIP on main: 8a280fe init\n\t\t// error: pathspec ':(prefix:0)b.txt' did not match any file(s) known to git\n\t\t//\n\t\t// Only suppress --keep-index for that case — when the selection actually includes untracked\n\t\t// files (`includeUntracked`) AND we're stashing by pathspec. Keying off `includeUntracked` (the\n\t\t// caller's intent) rather than the `--include-untracked` flag is deliberate: we add\n\t\t// `--include-untracked` to every pathspec push above as a safety net, but a tracked-only\n\t\t// selection can — and must — still keep the index intact.\n\t\tif (options?.keepIndex && !(options?.includeUntracked && options?.pathspecs?.length)) {\n\t\t\tparams.push('--keep-index');\n\t\t}\n\n\t\tif (options?.onlyStaged) {\n\t\t\tif (await this.git.supports('git:stash:push:staged')) {\n\t\t\t\tparams.push('--staged');\n\t\t\t} else {\n\t\t\t\tthrow new Error(\n\t\t\t\t\tl10n.t(\n\t\t\t\t\t\t'Git version {0} or higher is required for --staged',\n\t\t\t\t\t\tString(gitFeaturesByVersion.get('git:stash:push:staged')),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\n\t\tif (message) {\n\t\t\tparams.push('-m', message);\n\t\t}\n\n\t\tlet stdin;\n\t\tif (options?.pathspecs?.length) {\n\t\t\tif (options.stdin) {\n\t\t\t\tstdin = options.pathspecs.join('\\0');\n\t\t\t\tparams.push('--pathspec-from-file=-', '--pathspec-file-nul', '--');\n\t\t\t} else {\n\t\t\t\tparams.push('--', ...options.pathspecs);\n\t\t\t}\n\t\t} else {\n\t\t\tparams.push('--');\n\t\t}\n\n\t\tlet nothingToSave = false;\n\t\ttry {\n\t\t\tconst result = await this.git.run({ cwd: repoPath, ...runOptions, stdin: stdin }, ...params);\n\t\t\tif (GitErrors.stashNothingToSave.test(result.stdout)) {\n\t\t\t\tnothingToSave = true;\n\t\t\t\tthrow new StashPushError({\n\t\t\t\t\treason: 'nothingToSave',\n\t\t\t\t\tgitCommand: { repoPath: repoPath, args: params },\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (ex) {\n\t\t\tif (ex instanceof StashPushError || isCancellationError(ex)) throw ex;\n\n\t\t\tthrow getGitCommandError(\n\t\t\t\t'stash-push',\n\t\t\t\tex,\n\t\t\t\treason =>\n\t\t\t\t\tnew StashPushError(\n\t\t\t\t\t\t{ reason: reason ?? 'other', gitCommand: { repoPath: repoPath, args: params } },\n\t\t\t\t\t\tex,\n\t\t\t\t\t),\n\t\t\t);\n\t\t} finally {\n\t\t\t// A failed or cancelled push may already have stashed, and reset the working tree; one with nothing to\n\t\t\t// save changed nothing\n\t\t\tif (!nothingToSave) {\n\t\t\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes', 'status');\n\t\t\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t\t\t}\n\t\t}\n\t}\n\n\t@debug()\n\tasync saveSnapshot(repoPath: string, message?: string): Promise<void> {\n\t\tconst result = await this.git.run({ cwd: repoPath }, 'stash', 'create');\n\t\tconst id = result.stdout.trim() || undefined;\n\t\tif (id == null) return;\n\n\t\tconst args = [];\n\t\tif (message) {\n\t\t\targs.push('-m', message);\n\t\t}\n\t\ttry {\n\t\t\tawait this.git.run({ cwd: repoPath }, 'stash', 'store', ...args, id);\n\t\t} finally {\n\t\t\tthis.announceStashChanged(repoPath);\n\t\t}\n\t}\n\n\tprivate announceStashChanged(repoPath: string): void {\n\t\tthis.context.hooks?.cache?.onReset?.(repoPath, 'stashes');\n\t\tthis.context.hooks?.repository?.onChanged?.(repoPath, ['stash']);\n\t}\n}\n\nexport function convertStashesToStdin(stashOrStashes: GitStash | ReadonlyMap<string, GitStashCommit> | undefined): {\n\treadonly stdin: string | undefined;\n\treadonly stashes: Map<string, GitStashCommit>;\n\treadonly remappedIds: Map<string, string>;\n} {\n\tconst remappedIds = new Map<string, string>();\n\tif (stashOrStashes == null) return { stdin: undefined, stashes: new Map(), remappedIds: remappedIds };\n\n\tlet stdin: string | undefined;\n\tconst original = 'stashes' in stashOrStashes ? stashOrStashes.stashes : stashOrStashes;\n\tconst stashes = new Map<string, GitStashCommit>(original);\n\n\tif (original.size) {\n\t\tstdin = '';\n\t\tfor (const stash of original.values()) {\n\t\t\tstdin += `${stash.sha.substring(0, 9)}\\n`;\n\t\t\t// Include the stash's 2nd (index files) and 3rd (untracked files) parents (if they aren't already in the map)\n\t\t\tfor (const p of skip(stash.parents, 1)) {\n\t\t\t\tremappedIds.set(p, stash.sha);\n\n\t\t\t\tif (!stashes.has(p)) {\n\t\t\t\t\tstashes.set(p, stash);\n\t\t\t\t\tstdin += `${p.substring(0, 9)}\\n`;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { stdin: stdin || undefined, stashes: stashes, remappedIds: remappedIds };\n}\n\nconst stashSummaryRegex =\n\t// oxlint-disable-next-line no-control-regex\n\t/(?:(?:(?<wip>WIP) on|On) (?<onref>[^/](?!.*\\/\\.)(?!.*\\.\\.)(?!.*\\/\\/)(?!.*@\\{)[^\\x00-\\x1F\\x7F ~^:?*[\\\\]+[^./]):\\s*)?(?<summary>.*)$/s;\n\nfunction createStash(\n\ts: ParsedStash | ParsedStashWithFiles,\n\trepoPath: string,\n\tcurrentUser: GitUser | undefined,\n): GitStashCommit {\n\t// `onRef` comes from the commit subject (%s), which git always prefixes with `On <branch>: …`\n\t// or `WIP on <branch>: …`. This holds even when the reflog message was customized\n\t// (autostash, `git stash store -m \"…\"`), so it's a reliable source\n\tlet onRef: string | undefined;\n\tconst subjectMatch = stashSummaryRegex.exec((s.commitSubject ?? '').trim());\n\tif (subjectMatch?.groups?.onref) {\n\t\tonRef = subjectMatch.groups.onref;\n\t}\n\n\t// The user-visible display message is derived from the reflog subject (%gs) so that short\n\t// custom messages like \"wip\", \"q\", or \"show args\" stay as the user wrote them instead of\n\t// being replaced by the verbose git-auto subject\n\tlet message = s.summary.trim();\n\tconst reflogMatch = stashSummaryRegex.exec(message);\n\tif (reflogMatch?.groups != null) {\n\t\tconst summary = reflogMatch.groups.summary.trim();\n\t\tif (summary.length === 0) {\n\t\t\tmessage = 'WIP';\n\t\t} else if (reflogMatch.groups.wip) {\n\t\t\tmessage = `WIP: ${summary}`;\n\t\t} else {\n\t\t\tmessage = summary;\n\t\t}\n\t}\n\n\tconst index = message.indexOf('\\n');\n\n\treturn new GitCommit(\n\t\trepoPath,\n\t\ts.sha,\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.authorDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tnew GitCommitIdentity(\n\t\t\tcurrentUser?.name ?? '',\n\t\t\tcurrentUser?.email,\n\t\t\tnew Date(Number(s.committedDate) * 1000),\n\t\t\tundefined,\n\t\t\ttrue,\n\t\t),\n\t\tindex !== -1 ? message.substring(0, index) : message,\n\t\ts.parents.split(' ') ?? [],\n\t\tmessage,\n\t\tcreateCommitFileset(s, repoPath, undefined),\n\t\ts.stats,\n\t\tundefined,\n\t\tundefined,\n\t\ts.stashName,\n\t\tonRef,\n\t) as GitStashCommit;\n}\n"],"mappings":"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"}
|
|
@@ -67,7 +67,9 @@ export declare class StatusGitSubProvider implements GitStatusSubProvider {
|
|
|
67
67
|
hasConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<boolean>;
|
|
68
68
|
getConflictingFiles(repoPath: string, cancellation?: AbortSignal): Promise<GitConflictFile[]>;
|
|
69
69
|
private hasUntrackedFiles;
|
|
70
|
-
getUntrackedFiles(repoPath: string,
|
|
70
|
+
getUntrackedFiles(repoPath: string, options?: {
|
|
71
|
+
paths?: readonly string[];
|
|
72
|
+
}, cancellation?: AbortSignal): Promise<GitFile[]>;
|
|
71
73
|
}
|
|
72
74
|
//#endregion
|
|
73
75
|
//# sourceMappingURL=status.d.ts.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { chunkByStringLength } from "../../utils/iterable.js";
|
|
1
2
|
import { raceWithTimeout } from "../../utils/cancellation.js";
|
|
2
3
|
import { iterateByDelimiter } from "../../utils/string.js";
|
|
3
4
|
import { getScopedLogger } from "../../utils/logger.scoped.js";
|
|
@@ -8,7 +9,7 @@ import { toFsPath } from "../../utils/uri.js";
|
|
|
8
9
|
import { normalizePath, splitPath, stripFolderGlob } from "../../utils/path.js";
|
|
9
10
|
import { PromiseMap } from "../../utils/promiseCache.js";
|
|
10
11
|
import __decorate from "../../_virtual/@oxc-project+runtime/helpers/esm/decorate.js";
|
|
11
|
-
import { GitErrors, defaultExceptionHandler, gitConfigsStatus } from "../exec/git.js";
|
|
12
|
+
import { GitErrors, defaultExceptionHandler, gitConfigsStatus, maxGitCliLength } from "../exec/git.js";
|
|
12
13
|
import { GitFileWorkingTreeStatus } from "../../git/models/fileStatus.js";
|
|
13
14
|
import _usingCtx from "../../_virtual/@oxc-project+runtime/helpers/esm/usingCtx.js";
|
|
14
15
|
import { parseGitConflictFiles } from "../parsers/indexParser.js";
|
|
@@ -289,29 +290,46 @@ var StatusGitSubProvider = class {
|
|
|
289
290
|
_usingCtx3.d();
|
|
290
291
|
}
|
|
291
292
|
}
|
|
292
|
-
getUntrackedFiles(repoPath, cancellation) {
|
|
293
|
+
getUntrackedFiles(repoPath, options, cancellation) {
|
|
293
294
|
const scope = getScopedLogger();
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
295
|
+
const paths = options?.paths;
|
|
296
|
+
if (paths != null && !paths.length) return Promise.resolve([]);
|
|
297
|
+
const pathspecs = paths?.map((p) => `:(literal)${p}`);
|
|
298
|
+
const read = pathspecs != null ? `getUntrackedFiles\0${pathspecs.join("\0")}` : "getUntrackedFiles";
|
|
299
|
+
return this.dedupeByStatusGeneration(repoPath, read, async (correlationKey, signal) => {
|
|
300
|
+
const prefix = [
|
|
301
|
+
"ls-files",
|
|
302
|
+
"-z",
|
|
303
|
+
"--others",
|
|
304
|
+
"--exclude-standard"
|
|
305
|
+
];
|
|
306
|
+
let batches = [[]];
|
|
307
|
+
if (pathspecs != null) {
|
|
308
|
+
const perArgOverhead = 3;
|
|
309
|
+
const prefixLength = [...prefix, "--"].reduce((sum, arg) => sum + arg.length + perArgOverhead, 0);
|
|
310
|
+
batches = chunkByStringLength(pathspecs, maxGitCliLength - prefixLength, perArgOverhead);
|
|
304
311
|
}
|
|
312
|
+
const seen = /* @__PURE__ */ new Set();
|
|
305
313
|
const files = [];
|
|
306
|
-
for (const
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
});
|
|
314
|
+
for (const batch of batches) {
|
|
315
|
+
const result = await this.git.run({
|
|
316
|
+
cwd: repoPath,
|
|
317
|
+
cancellation: signal,
|
|
318
|
+
errors: "throw",
|
|
319
|
+
correlationKey
|
|
320
|
+
}, ...prefix, ...pathspecs != null ? ["--", ...batch] : []);
|
|
321
|
+
if (!result.stdout) continue;
|
|
322
|
+
for (const line of iterateByDelimiter(result.stdout, "\0")) {
|
|
323
|
+
if (!line.length || seen.has(line)) continue;
|
|
324
|
+
seen.add(line);
|
|
325
|
+
files.push({
|
|
326
|
+
path: line,
|
|
327
|
+
repoPath,
|
|
328
|
+
status: GitFileWorkingTreeStatus.Untracked
|
|
329
|
+
});
|
|
330
|
+
}
|
|
313
331
|
}
|
|
314
|
-
scope?.addExitInfo(`${String(files.length)} untracked file(s)`);
|
|
332
|
+
scope?.addExitInfo(files.length ? `${String(files.length)} untracked file(s)` : "no untracked files");
|
|
315
333
|
return files;
|
|
316
334
|
}, cancellation);
|
|
317
335
|
}
|