From f894aceb63dff759ac4ab30d30c8da42244eb470 Mon Sep 17 00:00:00 2001 From: Eric Amodio Date: Sun, 9 Jan 2022 01:20:32 -0500 Subject: [PATCH] Updates branches & tags caching Avoids default params to reduce garbage --- src/env/node/git/localGitProvider.ts | 262 +++++++++++++++++------------------ 1 file changed, 125 insertions(+), 137 deletions(-) diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index 76fdff7..6d714b3 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -104,7 +104,8 @@ import { Git, GitErrors, maxGitCliLength } from './git'; import { findGitPath, GitLocation, InvalidGitConfigError, UnableToFindGitError } from './locator'; import { fsExists, RunError } from './shell'; -const emptyStr = ''; +const emptyPromise: Promise = Promise.resolve(undefined); +const emptyPagedResult: PagedResult = Object.freeze({ values: [] }); const RepoSearchWarnings = { doesNotExist: /no such file or directory/i, @@ -115,7 +116,6 @@ const driveLetterRegex = /(?<=^\/?)([a-zA-Z])(?=:\/)/; const userConfigRegex = /^user\.(name|email) (.*)$/gm; const mappedAuthorRegex = /(.+)\s<(.+)>/; -const emptyPromise: Promise = Promise.resolve(undefined); const reflogCommands = ['merge', 'pull']; export class LocalGitProvider implements GitProvider, Disposable { @@ -126,13 +126,13 @@ export class LocalGitProvider implements GitProvider, Disposable { return this._onDidChangeRepository.event; } - private readonly _branchesCache = new Map>(); + private readonly _branchesCache = new Map>>(); private readonly _contributorsCache = new Map>(); private readonly _mergeStatusCache = new Map(); private readonly _rebaseStatusCache = new Map(); private readonly _remotesWithApiProviderCache = new Map | null>(); private readonly _stashesCache = new Map(); - private readonly _tagsCache = new Map>(); + private readonly _tagsCache = new Map>>(); private readonly _trackedCache = new Map>(); private readonly _userMapCache = new Map(); @@ -339,7 +339,7 @@ export class LocalGitProvider implements GitProvider, Disposable { prefix: (context, folder) => `${context.prefix}(${folder.uri.fsPath})`, exit: result => `returned ${result.length} repositories${ - result.length !== 0 ? ` (${result.map(r => r.path).join(', ')})` : emptyStr + result.length !== 0 ? ` (${result.map(r => r.path).join(', ')})` : '' }`, }) private async repositorySearch(folder: WorkspaceFolder): Promise { @@ -382,9 +382,9 @@ export class LocalGitProvider implements GitProvider, Disposable { try { repoPaths = await this.repositorySearchCore(uri.fsPath, depth, excludes); } catch (ex) { - const msg: string = ex?.toString() ?? emptyStr; + const msg: string = ex?.toString() ?? ''; if (RepoSearchWarnings.doesNotExist.test(msg)) { - Logger.log(cc, `FAILED${msg ? ` Error: ${msg}` : emptyStr}`); + Logger.log(cc, `FAILED${msg ? ` Error: ${msg}` : ''}`); } else { Logger.error(ex, cc, 'FAILED'); } @@ -480,7 +480,7 @@ export class LocalGitProvider implements GitProvider, Disposable { patch = await Git.diff(uri.repoPath, uri.fsPath, ref1, ref2); void (await Git.apply(uri.repoPath, patch)); } catch (ex) { - const msg: string = ex?.toString() ?? emptyStr; + const msg: string = ex?.toString() ?? ''; if (patch && /patch does not apply/i.test(msg)) { const result = await window.showWarningMessage( 'Unable to apply changes cleanly. Retry and allow conflicts?', @@ -525,7 +525,7 @@ export class LocalGitProvider implements GitProvider, Disposable { try { await Git.checkout(repoPath, ref, options); } catch (ex) { - const msg: string = ex?.toString() ?? emptyStr; + const msg: string = ex?.toString() ?? ''; if (/overwritten by checkout/i.test(msg)) { void Messages.showGenericErrorMessage( `Unable to checkout '${ref}'. Please commit or stash your changes before switching branches`, @@ -592,9 +592,9 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async fetch( repoPath: string, - options: { all?: boolean; branch?: GitBranchReference; prune?: boolean; pull?: boolean; remote?: string } = {}, + options?: { all?: boolean; branch?: GitBranchReference; prune?: boolean; pull?: boolean; remote?: string }, ): Promise { - const { branch: branchRef, ...opts } = options; + const { branch: branchRef, ...opts } = options ?? {}; if (GitReference.isBranch(branchRef)) { const repo = await this.container.git.getRepository(repoPath); const branch = await repo?.getBranch(branchRef?.name); @@ -604,7 +604,7 @@ export class LocalGitProvider implements GitProvider, Disposable { branch: branch.getNameWithoutRemote(), remote: branch.getRemoteName()!, upstream: branch.getTrackingWithoutRemote()!, - pull: options.pull, + pull: options?.pull, }); } @@ -1010,16 +1010,16 @@ export class LocalGitProvider implements GitProvider, Disposable { @log({ args: { 1: false } }) async getBranches( repoPath: string | undefined, - options: { + options?: { filter?: (b: GitBranch) => boolean; sort?: boolean | BranchSortOptions; - } = {}, + }, ): Promise> { - if (repoPath == null) return { values: [] }; + if (repoPath == null) return emptyPagedResult; - let branchesPromise = this.useCaching ? this._branchesCache.get(repoPath) : undefined; - if (branchesPromise == null) { - async function load(this: LocalGitProvider) { + let resultsPromise = this.useCaching ? this._branchesCache.get(repoPath) : undefined; + if (resultsPromise == null) { + async function load(this: LocalGitProvider): Promise> { try { const data = await Git.for_each_ref__branch(repoPath!, { all: true }); // If we don't get any data, assume the repo doesn't have any commits yet so check if we have a current branch @@ -1052,21 +1052,21 @@ export class LocalGitProvider implements GitProvider, Disposable { ); } - return current != null ? [current] : []; + return current != null ? { values: [current] } : emptyPagedResult; } - return GitBranchParser.parse(data, repoPath!); + return { values: GitBranchParser.parse(data, repoPath!) }; } catch (ex) { this._branchesCache.delete(repoPath!); - return []; + return emptyPagedResult; } } - branchesPromise = load.call(this); + resultsPromise = load.call(this); if (this.useCaching) { - this._branchesCache.set(repoPath, branchesPromise); + this._branchesCache.set(repoPath, resultsPromise); if (!(await this.container.git.getRepository(repoPath))?.supportsChangeEvents) { this._branchesCache.delete(repoPath); @@ -1074,17 +1074,20 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - let branches = await branchesPromise; - if (options.filter != null) { - branches = branches.filter(options.filter); + let result = await resultsPromise; + if (options?.filter != null) { + result = { + ...result, + values: result.values.filter(options.filter), + }; } // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (options.sort) { - GitBranch.sort(branches, typeof options.sort === 'boolean' ? undefined : options.sort); + if (options?.sort) { + GitBranch.sort(result.values, typeof options.sort === 'boolean' ? undefined : options.sort); } - return { values: branches }; + return result; } // @log() @@ -1187,23 +1190,26 @@ export class LocalGitProvider implements GitProvider, Disposable { async getCommitForFile( repoPath: string | undefined, uri: Uri, - options: { ref?: string; firstIfNotFound?: boolean; range?: Range; reverse?: boolean } = {}, + options?: { ref?: string; firstIfNotFound?: boolean; range?: Range; reverse?: boolean }, ): Promise { const cc = Logger.getCorrelationContext(); try { const log = await this.getLogForFile(repoPath, uri.fsPath, { limit: 2, - ref: options.ref, - range: options.range, - reverse: options.reverse, + ref: options?.ref, + range: options?.range, + reverse: options?.reverse, }); if (log == null) return undefined; - const commit = options.ref ? log.commits.get(options.ref) : undefined; - if (commit == null && !options.firstIfNotFound && options.ref) { - // If the ref isn't a valid sha we will never find it, so let it fall through so we return the first - if (GitRevision.isSha(options.ref) || GitRevision.isUncommitted(options.ref)) return undefined; + let commit; + if (options?.ref) { + const commit = log.commits.get(options.ref); + if (commit == null && !options?.firstIfNotFound) { + // If the ref isn't a valid sha we will never find it, so let it fall through so we return the first + if (GitRevision.isSha(options.ref) || GitRevision.isUncommitted(options.ref)) return undefined; + } } return commit ?? Iterables.first(log.commits.values()); @@ -1581,7 +1587,7 @@ export class LocalGitProvider implements GitProvider, Disposable { repoPath: string, ref1?: string, ref2?: string, - options: { filters?: GitDiffFilter[]; similarityThreshold?: number } = {}, + options?: { filters?: GitDiffFilter[]; similarityThreshold?: number }, ): Promise { try { const data = await Git.diff__name_status(repoPath, ref1, ref2, { @@ -1611,10 +1617,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getLog( repoPath: string, - { - ref, - ...options - }: { + options?: { all?: boolean; authors?: string[]; limit?: number; @@ -1623,16 +1626,16 @@ export class LocalGitProvider implements GitProvider, Disposable { ref?: string; reverse?: boolean; since?: string; - } = {}, + }, ): Promise { - const limit = options.limit ?? this.container.config.advanced.maxListItems ?? 0; + const limit = options?.limit ?? this.container.config.advanced.maxListItems ?? 0; try { - const data = await Git.log(repoPath, ref, { + const data = await Git.log(repoPath, options?.ref, { ...options, limit: limit, - merges: options.merges == null ? true : options.merges, - ordering: options.ordering ?? this.container.config.advanced.commitOrdering, + merges: options?.merges == null ? true : options.merges, + ordering: options?.ordering ?? this.container.config.advanced.commitOrdering, similarityThreshold: this.container.config.advanced.similarityThreshold, }); const log = GitLogParser.parse( @@ -1640,18 +1643,17 @@ export class LocalGitProvider implements GitProvider, Disposable { GitCommitType.Log, repoPath, undefined, - ref, + options?.ref, await this.getCurrentUser(repoPath), limit, - options.reverse!, + options?.reverse ?? false, undefined, ); if (log != null) { - const opts = { ...options, ref: ref }; - log.query = (limit: number | undefined) => this.getLog(repoPath, { ...opts, limit: limit }); + log.query = (limit: number | undefined) => this.getLog(repoPath, { ...options, limit: limit }); if (log.hasMore) { - log.more = this.getLogMoreFn(log, opts); + log.more = this.getLogMoreFn(log, options); } } @@ -1664,10 +1666,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getLogRefsOnly( repoPath: string, - { - ref, - ...options - }: { + options?: { authors?: string[]; limit?: number; merges?: boolean; @@ -1675,20 +1674,20 @@ export class LocalGitProvider implements GitProvider, Disposable { ref?: string; reverse?: boolean; since?: string; - } = {}, + }, ): Promise | undefined> { - const limit = options.limit ?? this.container.config.advanced.maxListItems ?? 0; + const limit = options?.limit ?? this.container.config.advanced.maxListItems ?? 0; try { - const data = await Git.log(repoPath, ref, { - authors: options.authors, + const data = await Git.log(repoPath, options?.ref, { + authors: options?.authors, format: 'refs', limit: limit, - merges: options.merges == null ? true : options.merges, - reverse: options.reverse, + merges: options?.merges == null ? true : options.merges, + reverse: options?.reverse, similarityThreshold: this.container.config.advanced.similarityThreshold, - since: options.since, - ordering: options.ordering ?? this.container.config.advanced.commitOrdering, + since: options?.since, + ordering: options?.ordering ?? this.container.config.advanced.commitOrdering, }); const commits = GitLogParser.parseRefsOnly(data); return new Set(commits); @@ -1699,7 +1698,7 @@ export class LocalGitProvider implements GitProvider, Disposable { private getLogMoreFn( log: GitLog, - options: { + options?: { authors?: string[]; limit?: number; merges?: boolean; @@ -1722,7 +1721,7 @@ export class LocalGitProvider implements GitProvider, Disposable { if (GitRevision.isRange(log.sha)) { const moreLog = await this.getLog(log.repoPath, { ...options, - limit: moreLimit === 0 ? 0 : (options.limit ?? 0) + moreLimit, + limit: moreLimit === 0 ? 0 : (options?.limit ?? 0) + moreLimit, }); // If we can't find any more, assume we have everything if (moreLog == null) return { ...log, hasMore: false }; @@ -1773,12 +1772,12 @@ export class LocalGitProvider implements GitProvider, Disposable { async getLogForSearch( repoPath: string, search: SearchPattern, - options: { limit?: number; ordering?: string | null; skip?: number } = {}, + options?: { limit?: number; ordering?: string | null; skip?: number }, ): Promise { search = { matchAll: false, matchCase: false, matchRegex: true, ...search }; try { - const limit = options.limit ?? this.container.config.advanced.maxSearchItems ?? 0; + const limit = options?.limit ?? this.container.config.advanced.maxSearchItems ?? 0; const similarityThreshold = this.container.config.advanced.similarityThreshold; const operations = SearchPattern.parseSearchOperations(search.pattern); @@ -1893,7 +1892,7 @@ export class LocalGitProvider implements GitProvider, Disposable { private getLogForSearchMoreFn( log: GitLog, search: SearchPattern, - options: { limit?: number; ordering?: string | null }, + options?: { limit?: number; ordering?: string | null }, ): (limit: number | undefined) => Promise { return async (limit: number | undefined) => { limit = limit ?? this.container.config.advanced.maxSearchItems ?? 0; @@ -1942,7 +1941,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async getLogForFile( repoPath: string | undefined, fileName: string, - options: { + options?: { all?: boolean; limit?: number; ordering?: string | null; @@ -1952,7 +1951,7 @@ export class LocalGitProvider implements GitProvider, Disposable { reverse?: boolean; since?: string; skip?: number; - } = {}, + }, ): Promise { if (repoPath != null && repoPath === Strings.normalizePath(fileName)) { throw new Error(`File name cannot match the repository path; fileName=${fileName}`); @@ -2011,7 +2010,7 @@ export class LocalGitProvider implements GitProvider, Disposable { if (options.ref != null || options.limit != null) { // Since we are looking for partial log, see if we have the log of the whole file const cachedLog = doc.state.get( - `log${options.renames ? ':follow' : emptyStr}${options.reverse ? ':reverse' : emptyStr}`, + `log${options.renames ? ':follow' : ''}${options.reverse ? ':reverse' : ''}`, ); if (cachedLog != null) { if (options.ref == null) { @@ -2033,12 +2032,12 @@ export class LocalGitProvider implements GitProvider, Disposable { log.commits.entries(), ([ref, c]) => { if (skip) { - if (ref !== options.ref) return undefined; + if (ref !== options?.ref) return undefined; skip = false; } i++; - if (options.limit != null && i > options.limit) { + if (options?.limit != null && i > options.limit) { return undefined; } @@ -2199,10 +2198,8 @@ export class LocalGitProvider implements GitProvider, Disposable { ref: options.all ? undefined : moreUntil == null ? `${ref}^` : `${moreUntil}^..${ref}^`, skip: options.all ? log.count : undefined, }); - if (moreLog == null) { - // If we can't find any more, assume we have everything - return { ...log, hasMore: false }; - } + // If we can't find any more, assume we have everything + if (moreLog == null) return { ...log, hasMore: false }; // Merge authors const authors = new Map([...log.authors]); @@ -2247,7 +2244,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getMergeBase(repoPath: string, ref1: string, ref2: string, options: { forkPoint?: boolean } = {}) { + async getMergeBase(repoPath: string, ref1: string, ref2: string, options?: { forkPoint?: boolean }) { const cc = Logger.getCorrelationContext(); try { @@ -2708,7 +2705,7 @@ export class LocalGitProvider implements GitProvider, Disposable { startLine: editorLine != null ? editorLine + 1 : undefined, }); } catch (ex) { - const msg: string = ex?.toString() ?? emptyStr; + const msg: string = ex?.toString() ?? ''; // If the line count is invalid just fallback to the most recent commit if ((ref == null || GitRevision.isUncommittedStaged(ref)) && GitErrors.invalidLineCount.test(msg)) { if (ref == null) { @@ -2809,7 +2806,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async getPullRequestForCommit( ref: string, remoteOrProvider: GitRemote | RichRemoteProvider, - { timeout }: { timeout?: number } = {}, + options?: { timeout?: number }, ): Promise { if (GitRevision.isUncommitted(ref)) return undefined; @@ -2826,8 +2823,8 @@ export class LocalGitProvider implements GitProvider, Disposable { return promiseOrPR; } - if (timeout != null && timeout > 0) { - promiseOrPR = Promises.cancellable(promiseOrPR, timeout); + if (options?.timeout != null && options.timeout > 0) { + promiseOrPR = Promises.cancellable(promiseOrPR, options.timeout); } try { @@ -2844,14 +2841,11 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getIncomingActivity( repoPath: string, - { - limit, - ...options - }: { all?: boolean; branch?: string; limit?: number; ordering?: string | null; skip?: number } = {}, + options?: { all?: boolean; branch?: string; limit?: number; ordering?: string | null; skip?: number }, ): Promise { const cc = Logger.getCorrelationContext(); - limit = limit ?? this.container.config.advanced.maxListItems ?? 0; + const limit = options?.limit ?? this.container.config.advanced.maxListItems ?? 0; try { // Pass a much larger limit to reflog, because we aggregate the data and we won't know how many lines we'll need const data = await Git.reflog(repoPath, { @@ -2875,7 +2869,7 @@ export class LocalGitProvider implements GitProvider, Disposable { private getReflogMoreFn( reflog: GitReflog, - options: { all?: boolean; branch?: string; limit?: number; ordering?: string | null; skip?: number }, + options?: { all?: boolean; branch?: string; limit?: number; ordering?: string | null; skip?: number }, ): (limit: number) => Promise { return async (limit: number | undefined) => { limit = limit ?? this.container.config.advanced.maxSearchItems ?? 0; @@ -2926,7 +2920,7 @@ export class LocalGitProvider implements GitProvider, Disposable { }) async getRichRemoteProvider( remotesOrRepoPath: GitRemote[] | string | undefined, - { includeDisconnected }: { includeDisconnected?: boolean } = {}, + options?: { includeDisconnected?: boolean }, ): Promise | undefined> { if (remotesOrRepoPath == null) return undefined; @@ -2934,9 +2928,9 @@ export class LocalGitProvider implements GitProvider, Disposable { let richRemote = this._remotesWithApiProviderCache.get(cacheKey); if (richRemote != null) return richRemote; - if (richRemote === null && !includeDisconnected) return undefined; + if (richRemote === null && !options?.includeDisconnected) return undefined; - if (includeDisconnected) { + if (options?.includeDisconnected) { richRemote = this._remotesWithApiProviderCache.get(`disconnected|${cacheKey}`); if (richRemote !== undefined) return richRemote ?? undefined; } @@ -2999,23 +2993,20 @@ export class LocalGitProvider implements GitProvider, Disposable { this._remotesWithApiProviderCache.set(cacheKey, null); this._remotesWithApiProviderCache.set(`disconnected|${cacheKey}`, remote); - if (!includeDisconnected) return undefined; + if (!options?.includeDisconnected) return undefined; } return remote; } @log() - async getRemotes( - repoPath: string | undefined, - options: { sort?: boolean } = {}, - ): Promise[]> { + async getRemotes(repoPath: string | undefined, options?: { sort?: boolean }): Promise[]> { if (repoPath == null) return []; const repository = await this.container.git.getRepository(repoPath); const remotes = await (repository != null - ? repository.getRemotes({ sort: options.sort }) - : this.getRemotesCore(repoPath, undefined, { sort: options.sort })); + ? repository.getRemotes(options) + : this.getRemotesCore(repoPath, undefined, options)); return remotes.filter(r => r.provider != null) as GitRemote[]; } @@ -3023,7 +3014,7 @@ export class LocalGitProvider implements GitProvider, Disposable { async getRemotesCore( repoPath: string | undefined, providers?: RemoteProviders, - options: { sort?: boolean } = {}, + options?: { sort?: boolean }, ): Promise { if (repoPath == null) return []; @@ -3034,7 +3025,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const remotes = GitRemoteParser.parse(data, repoPath, RemoteProviderFactory.factory(providers)); if (remotes == null) return []; - if (options.sort) { + if (options?.sort) { GitRemote.sort(remotes); } @@ -3244,27 +3235,27 @@ export class LocalGitProvider implements GitProvider, Disposable { @log({ args: { 1: false } }) async getTags( repoPath: string | undefined, - options: { filter?: (t: GitTag) => boolean; sort?: boolean | TagSortOptions } = {}, + options?: { filter?: (t: GitTag) => boolean; sort?: boolean | TagSortOptions }, ): Promise> { - if (repoPath == null) return { values: [] }; + if (repoPath == null) return emptyPagedResult; - let tagsPromise = this.useCaching ? this._tagsCache.get(repoPath) : undefined; - if (tagsPromise == null) { - async function load(this: LocalGitProvider) { + let resultsPromise = this.useCaching ? this._tagsCache.get(repoPath) : undefined; + if (resultsPromise == null) { + async function load(this: LocalGitProvider): Promise> { try { const data = await Git.tag(repoPath!); - return GitTagParser.parse(data, repoPath!) ?? []; + return { values: GitTagParser.parse(data, repoPath!) ?? [] }; } catch (ex) { this._tagsCache.delete(repoPath!); - return []; + return emptyPagedResult; } } - tagsPromise = load.call(this); + resultsPromise = load.call(this); if (this.useCaching) { - this._tagsCache.set(repoPath, tagsPromise); + this._tagsCache.set(repoPath, resultsPromise); if (!(await this.container.git.getRepository(repoPath))?.supportsChangeEvents) { this._tagsCache.delete(repoPath); @@ -3272,17 +3263,20 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - let tags = await tagsPromise; - if (options.filter != null) { - tags = tags.filter(options.filter); + let result = await resultsPromise; + if (options?.filter != null) { + result = { + ...result, + values: result.values.filter(options.filter), + }; } // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (options.sort) { - GitTag.sort(tags, typeof options.sort === 'boolean' ? undefined : options.sort); + if (options?.sort) { + GitTag.sort(result.values, typeof options.sort === 'boolean' ? undefined : options.sort); } - return { values: tags }; + return result; } @log() @@ -3382,19 +3376,17 @@ export class LocalGitProvider implements GitProvider, Disposable { @log({ args: { 1: false } }) async hasBranchOrTag( repoPath: string | undefined, - { - filter, - }: { + options?: { filter?: { branches?: (b: GitBranch) => boolean; tags?: (t: GitTag) => boolean }; - } = {}, + }, ) { const [{ values: branches }, { values: tags }] = await Promise.all([ this.getBranches(repoPath, { - filter: filter?.branches, + filter: options?.filter?.branches, sort: false, }), this.getTags(repoPath, { - filter: filter?.tags, + filter: options?.filter?.tags, sort: false, }), ]); @@ -3477,7 +3469,7 @@ export class LocalGitProvider implements GitProvider, Disposable { let tracked = this._trackedCache.get(cacheKey); if (tracked != null) return tracked; - tracked = this.isTrackedCore(relativeFilePath, repoPath ?? emptyStr, ref); + tracked = this.isTrackedCore(relativeFilePath, repoPath ?? '', ref); this._trackedCache.set(cacheKey, tracked); tracked = await tracked; @@ -3518,20 +3510,20 @@ export class LocalGitProvider implements GitProvider, Disposable { async openDiffTool( repoPath: string, uri: Uri, - options: { ref1?: string; ref2?: string; staged?: boolean; tool?: string } = {}, + options?: { ref1?: string; ref2?: string; staged?: boolean; tool?: string }, ): Promise { try { - if (!options.tool) { + let tool = options?.tool; + if (!tool) { const cc = Logger.getCorrelationContext(); - options.tool = this.container.config.advanced.externalDiffTool || (await this.getDiffTool(repoPath)); - if (options.tool == null) throw new Error('No diff tool found'); + tool = this.container.config.advanced.externalDiffTool || (await this.getDiffTool(repoPath)); + if (tool == null) throw new Error('No diff tool found'); - Logger.log(cc, `Using tool=${options.tool}`); + Logger.log(cc, `Using tool=${tool}`); } - const { tool, ...opts } = options; - await Git.difftool(repoPath, uri.fsPath, tool, opts); + await Git.difftool(repoPath, uri.fsPath, tool, options); } catch (ex) { const msg: string = ex?.toString() ?? ''; if (msg === 'No diff tool found' || /Unknown .+? tool/.test(msg)) { @@ -3689,13 +3681,9 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async stashApply( - repoPath: string, - stashName: string, - { deleteAfter }: { deleteAfter?: boolean } = {}, - ): Promise { + async stashApply(repoPath: string, stashName: string, options?: { deleteAfter?: boolean }): Promise { try { - await Git.stash__apply(repoPath, stashName, Boolean(deleteAfter)); + await Git.stash__apply(repoPath, stashName, Boolean(options?.deleteAfter)); } catch (ex) { if (ex instanceof Error) { const msg: string = ex.message ?? ''; @@ -3739,7 +3727,7 @@ export class LocalGitProvider implements GitProvider, Disposable { repoPath: string, message?: string, uris?: Uri[], - options: { includeUntracked?: boolean; keepIndex?: boolean } = {}, + options?: { includeUntracked?: boolean; keepIndex?: boolean }, ): Promise { if (uris == null) return Git.stash__push(repoPath, message, options);