diff --git a/src/commands/closeUnchangedFiles.ts b/src/commands/closeUnchangedFiles.ts index 0ff2662eac042..6831d8db85ac2 100644 --- a/src/commands/closeUnchangedFiles.ts +++ b/src/commands/closeUnchangedFiles.ts @@ -27,7 +27,7 @@ export class CloseUnchangedFilesCommand extends Command { const repository = await getRepositoryOrShowPicker('Close All Unchanged Files'); if (repository == null) return; - const status = await this.container.git.getStatusForRepo(repository.uri); + const status = await this.container.git.getStatus(repository.uri); if (status == null) { void window.showWarningMessage('Unable to close unchanged files'); diff --git a/src/commands/copyCurrentBranch.ts b/src/commands/copyCurrentBranch.ts index d5cf76ff2d4e1..b5a62d0aeaf3c 100644 --- a/src/commands/copyCurrentBranch.ts +++ b/src/commands/copyCurrentBranch.ts @@ -24,7 +24,7 @@ export class CopyCurrentBranchCommand extends ActiveEditorCommand { if (repository == null) return; try { - const branch = await repository.getBranch(); + const branch = await repository.git.getBranch(); if (branch?.name) { await env.clipboard.writeText(branch.name); } diff --git a/src/commands/createPullRequestOnRemote.ts b/src/commands/createPullRequestOnRemote.ts index 2a71c27eb92d7..a5f7201ab1f3f 100644 --- a/src/commands/createPullRequestOnRemote.ts +++ b/src/commands/createPullRequestOnRemote.ts @@ -35,7 +35,7 @@ export class CreatePullRequestOnRemoteCommand extends Command { if (repo == null) return; if (args == null) { - const branch = await repo.getBranch(); + const branch = await repo.git.getBranch(); if (branch?.upstream == null) { void window.showErrorMessage( `Unable to create a pull request for branch \`${branch?.name}\` because it has no upstream branch`, @@ -51,11 +51,11 @@ export class CreatePullRequestOnRemoteCommand extends Command { }; } - const compareRemote = await repo.getRemote(args.remote); + const compareRemote = await repo.git.getRemote(args.remote); if (compareRemote?.provider == null) return; const providerId = compareRemote.provider.id; - const remotes = (await repo.getRemotes({ + const remotes = (await repo.git.getRemotes({ filter: r => r.provider?.id === providerId, sort: true, })) as GitRemote[]; diff --git a/src/commands/diffWithRevision.ts b/src/commands/diffWithRevision.ts index a9f94b3273fc3..e7eaafacf38c4 100644 --- a/src/commands/diffWithRevision.ts +++ b/src/commands/diffWithRevision.ts @@ -61,7 +61,7 @@ export class DiffWithRevisionCommand extends ActiveEditorCommand { getState: async () => { const items: (CommandQuickPickItem | DirectiveQuickPickItem)[] = []; - const status = await this.container.git.getStatusForRepo(gitUri.repoPath); + const status = await this.container.git.getStatus(gitUri.repoPath); if (status != null) { for (const f of status.files) { if (f.workingTreeStatus === '?' || f.workingTreeStatus === '!') { diff --git a/src/commands/externalDiff.ts b/src/commands/externalDiff.ts index e3078675a9609..d4742765114a6 100644 --- a/src/commands/externalDiff.ts +++ b/src/commands/externalDiff.ts @@ -88,7 +88,7 @@ export class ExternalDiffCommand extends Command { const repository = await getRepositoryOrShowPicker('Open All Changes (difftool)'); if (repository == null) return undefined; - const status = await this.container.git.getStatusForRepo(repository.uri); + const status = await this.container.git.getStatus(repository.uri); if (status == null) { return window.showInformationMessage("The repository doesn't have any changes"); } diff --git a/src/commands/ghpr/openOrCreateWorktree.ts b/src/commands/ghpr/openOrCreateWorktree.ts index d904d6a55446a..ad5333516165c 100644 --- a/src/commands/ghpr/openOrCreateWorktree.ts +++ b/src/commands/ghpr/openOrCreateWorktree.ts @@ -86,7 +86,7 @@ export class OpenOrCreateWorktreeCommand extends Command { const remoteUrl = remoteUri.toString(); const [, remoteDomain, remotePath] = parseGitRemoteUrl(remoteUrl); - const remotes = await repo.getRemotes({ filter: r => r.matches(remoteDomain, remotePath) }); + const remotes = await repo.git.getRemotes({ filter: r => r.matches(remoteDomain, remotePath) }); const remote = remotes[0] as GitRemote | undefined; let addRemote: { name: string; url: string } | undefined; diff --git a/src/commands/git/branch.ts b/src/commands/git/branch.ts index 2e2377a408caf..b6938ca8cea9b 100644 --- a/src/commands/git/branch.ts +++ b/src/commands/git/branch.ts @@ -338,7 +338,7 @@ export class BranchGitCommand extends QuickCommand { const result = yield* pickBranchOrTagStep(state, context, { placeholder: context => `Choose a branch${context.showTags ? ' or tag' : ''} to create the new branch from`, - picked: state.reference?.ref ?? (await state.repo.getBranch())?.ref, + picked: state.reference?.ref ?? (await state.repo.git.getBranch())?.ref, titleContext: ' from', value: isRevisionReference(state.reference) ? state.reference.ref : undefined, }); diff --git a/src/commands/git/cherry-pick.ts b/src/commands/git/cherry-pick.ts index 1df599e04a0eb..4a6345c58ca9a 100644 --- a/src/commands/git/cherry-pick.ts +++ b/src/commands/git/cherry-pick.ts @@ -131,7 +131,7 @@ export class CherryPickGitCommand extends QuickCommand { } if (context.destination == null) { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); if (branch == null) break; context.destination = branch; @@ -179,7 +179,7 @@ export class CherryPickGitCommand extends QuickCommand { { mode: 'contains' }, ); if (branches.length) { - const branch = await state.repo.getBranch(branches[0]); + const branch = await state.repo.git.getBranch(branches[0]); if (branch != null) { context.selectedBranchOrTag = branch; } diff --git a/src/commands/git/log.ts b/src/commands/git/log.ts index 0db639fffd71f..43d6492c0ae19 100644 --- a/src/commands/git/log.ts +++ b/src/commands/git/log.ts @@ -118,7 +118,7 @@ export class LogGitCommand extends QuickCommand { assertStateStepRepository(state); if (state.reference === 'HEAD') { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); state.reference = branch; } diff --git a/src/commands/git/merge.ts b/src/commands/git/merge.ts index 34f08e4c01cc2..3d2ba5eb7e7c3 100644 --- a/src/commands/git/merge.ts +++ b/src/commands/git/merge.ts @@ -121,7 +121,7 @@ export class MergeGitCommand extends QuickCommand { } if (context.destination == null) { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); if (branch == null) break; context.destination = branch; diff --git a/src/commands/git/pull.ts b/src/commands/git/pull.ts index 7e57de3b5c17d..0626f983d18b5 100644 --- a/src/commands/git/pull.ts +++ b/src/commands/git/pull.ts @@ -67,7 +67,7 @@ export class PullGitCommand extends QuickCommand { if (isBranchReference(state.reference)) { // Only resort to a branch fetch if the branch isn't the current one if (!isBranch(state.reference) || !state.reference.current) { - const currentBranch = await state.repos[0].getBranch(); + const currentBranch = await state.repos[0].git.getBranch(); if (currentBranch?.name !== state.reference.name) { return state.repos[0].fetch({ branch: state.reference, pull: true }); } @@ -167,7 +167,7 @@ export class PullGitCommand extends QuickCommand { ); } else { const [repo] = state.repos; - const branch = await repo.getBranch(state.reference.name); + const branch = await repo.git.getBranch(state.reference.name); if (branch?.upstream == null) { step = this.createConfirmStep( @@ -193,7 +193,7 @@ export class PullGitCommand extends QuickCommand { } } else { const [repo] = state.repos; - const [status, lastFetched] = await Promise.all([repo.getStatus(), repo.getLastFetched()]); + const [status, lastFetched] = await Promise.all([repo.git.getStatus(), repo.getLastFetched()]); let lastFetchedOn = ''; if (lastFetched !== 0) { diff --git a/src/commands/git/push.ts b/src/commands/git/push.ts index 661e8146efb71..8e09d69cfae58 100644 --- a/src/commands/git/push.ts +++ b/src/commands/git/push.ts @@ -197,10 +197,10 @@ export class PushGitCommand extends QuickCommand { { placeholder: 'Cannot push a remote branch' }, ); } else { - const branch = await repo.getBranch(state.reference.name); + const branch = await repo.git.getBranch(state.reference.name); if (branch != null && branch?.upstream == null) { - for (const remote of await repo.getRemotes()) { + for (const remote of await repo.git.getRemotes()) { items.push( createFlagsQuickPickItem( state.flags, @@ -294,7 +294,7 @@ export class PushGitCommand extends QuickCommand { } } } else { - const status = await repo.getStatus(); + const status = await repo.git.getStatus(); const branch: GitBranchReference = { refType: 'branch', @@ -317,7 +317,7 @@ export class PushGitCommand extends QuickCommand { pushDetails = ''; } - for (const remote of await repo.getRemotes()) { + for (const remote of await repo.git.getRemotes()) { items.push( createFlagsQuickPickItem( state.flags, diff --git a/src/commands/git/rebase.ts b/src/commands/git/rebase.ts index 2166612a6f31e..f8f8b326a3050 100644 --- a/src/commands/git/rebase.ts +++ b/src/commands/git/rebase.ts @@ -131,7 +131,7 @@ export class RebaseGitCommand extends QuickCommand { } if (context.destination == null) { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); if (branch == null) break; context.destination = branch; diff --git a/src/commands/git/remote.ts b/src/commands/git/remote.ts index 2c4821096b915..6d3dbf22c560d 100644 --- a/src/commands/git/remote.ts +++ b/src/commands/git/remote.ts @@ -288,7 +288,7 @@ export class RemoteGitCommand extends QuickCommand { state.flags = ['-f']; } - let alreadyExists = (await state.repo.getRemotes({ filter: r => r.name === state.name })).length !== 0; + let alreadyExists = (await state.repo.git.getRemotes({ filter: r => r.name === state.name })).length !== 0; while (this.canStepsContinue(state)) { if (state.counter < 3 || state.name == null || alreadyExists) { @@ -298,7 +298,7 @@ export class RemoteGitCommand extends QuickCommand { }); if (result === StepResultBreak) continue; - alreadyExists = (await state.repo.getRemotes({ filter: r => r.name === result })).length !== 0; + alreadyExists = (await state.repo.git.getRemotes({ filter: r => r.name === result })).length !== 0; if (alreadyExists) { state.counter--; continue; @@ -360,7 +360,7 @@ export class RemoteGitCommand extends QuickCommand { while (this.canStepsContinue(state)) { if (state.remote != null) { if (typeof state.remote === 'string') { - const [remote] = await state.repo.getRemotes({ filter: r => r.name === state.remote }); + const [remote] = await state.repo.git.getRemotes({ filter: r => r.name === state.remote }); if (remote != null) { state.remote = remote; } else { @@ -386,7 +386,7 @@ export class RemoteGitCommand extends QuickCommand { endSteps(state); try { - await state.repo.removeRemote(state.remote.name); + await state.repo.git.removeRemote(state.remote.name); } catch (ex) { Logger.error(ex); void showGenericErrorMessage('Unable to remove remote'); @@ -416,7 +416,7 @@ export class RemoteGitCommand extends QuickCommand { while (this.canStepsContinue(state)) { if (state.remote != null) { if (typeof state.remote === 'string') { - const [remote] = await state.repo.getRemotes({ filter: r => r.name === state.remote }); + const [remote] = await state.repo.git.getRemotes({ filter: r => r.name === state.remote }); if (remote != null) { state.remote = remote; } else { @@ -441,7 +441,7 @@ export class RemoteGitCommand extends QuickCommand { if (result === StepResultBreak) continue; endSteps(state); - void state.repo.pruneRemote(state.remote.name); + void state.repo.git.pruneRemote(state.remote.name); } } diff --git a/src/commands/git/reset.ts b/src/commands/git/reset.ts index 4b72b477b993d..479703372aa1b 100644 --- a/src/commands/git/reset.ts +++ b/src/commands/git/reset.ts @@ -110,7 +110,7 @@ export class ResetGitCommand extends QuickCommand { } if (context.destination == null) { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); if (branch == null) break; context.destination = branch; diff --git a/src/commands/git/revert.ts b/src/commands/git/revert.ts index e1300d79cb3ed..5795e834611d9 100644 --- a/src/commands/git/revert.ts +++ b/src/commands/git/revert.ts @@ -116,7 +116,7 @@ export class RevertGitCommand extends QuickCommand { } if (context.destination == null) { - const branch = await state.repo.getBranch(); + const branch = await state.repo.git.getBranch(); if (branch == null) break; context.destination = branch; diff --git a/src/commands/git/search.ts b/src/commands/git/search.ts index 222eb3737679a..f900d48ca8701 100644 --- a/src/commands/git/search.ts +++ b/src/commands/git/search.ts @@ -208,7 +208,7 @@ export class SearchGitCommand extends QuickCommand { const searchKey = getSearchQueryComparisonKey(search); if (context.resultsPromise == null || context.resultsKey !== searchKey) { - context.resultsPromise = state.repo.richSearchCommits(search); + context.resultsPromise = state.repo.git.richSearchCommits(search); context.resultsKey = searchKey; } diff --git a/src/commands/git/status.ts b/src/commands/git/status.ts index 7b601d4173881..07a6bba0e4458 100644 --- a/src/commands/git/status.ts +++ b/src/commands/git/status.ts @@ -82,7 +82,7 @@ export class StatusGitCommand extends QuickCommand { } } - context.status = (await state.repo.getStatus())!; + context.status = (await state.repo.git.getStatus())!; if (context.status == null) return; context.title = `${this.title}${pad(GlyphChars.Dot, 2, 2)}${getReferenceLabel( diff --git a/src/commands/git/tag.ts b/src/commands/git/tag.ts index bc8ef75e08e61..263559b478410 100644 --- a/src/commands/git/tag.ts +++ b/src/commands/git/tag.ts @@ -243,7 +243,7 @@ export class TagGitCommand extends QuickCommand { const result = yield* pickBranchOrTagStep(state, context, { placeholder: context => `Choose a branch${context.showTags ? ' or tag' : ''} to create the new tag from`, - picked: state.reference?.ref ?? (await state.repo.getBranch())?.ref, + picked: state.reference?.ref ?? (await state.repo.git.getBranch())?.ref, titleContext: ' from', value: isRevisionReference(state.reference) ? state.reference.ref : undefined, }); diff --git a/src/commands/git/worktree.ts b/src/commands/git/worktree.ts index 9d5ac043e6463..c4e32bbd993ed 100644 --- a/src/commands/git/worktree.ts +++ b/src/commands/git/worktree.ts @@ -380,7 +380,7 @@ export class WorktreeGitCommand extends QuickCommand { private async *createCommandSteps(state: CreateStepState, context: Context): AsyncStepResultGenerator { if (context.defaultUri == null) { - context.defaultUri = await state.repo.getWorktreesDefaultUri(); + context.defaultUri = await state.repo.git.getWorktreesDefaultUri(); } if (state.flags == null) { @@ -399,7 +399,7 @@ export class WorktreeGitCommand extends QuickCommand { const result = yield* pickBranchOrTagStep(state, context, { placeholder: context => `Choose a branch${context.showTags ? ' or tag' : ''} to create the new worktree for`, - picked: state.reference?.ref ?? (await state.repo.getBranch())?.ref, + picked: state.reference?.ref ?? (await state.repo.git.getBranch())?.ref, titleContext: ' for', value: isRevisionReference(state.reference) ? state.reference.ref : undefined, }); @@ -425,7 +425,7 @@ export class WorktreeGitCommand extends QuickCommand { if (isRemoteBranch) { state.createBranch = getNameWithoutRemote(state.reference); - const branch = await state.repo.getBranch(state.createBranch); + const branch = await state.repo.git.getBranch(state.createBranch); if (branch != null && !branch.remote) { state.createBranch = branch.name; } @@ -436,7 +436,7 @@ export class WorktreeGitCommand extends QuickCommand { if (state.createBranch != null) { let valid = await this.container.git.validateBranchOrTagName(state.repo.path, state.createBranch); if (valid) { - const alreadyExists = await state.repo.getBranch(state.createBranch); + const alreadyExists = await state.repo.git.getBranch(state.createBranch); valid = alreadyExists == null; } @@ -830,7 +830,7 @@ export class WorktreeGitCommand extends QuickCommand { } private async *deleteCommandSteps(state: DeleteStepState, context: Context): StepGenerator { - context.worktrees = await state.repo.getWorktrees(); + context.worktrees = await state.repo.git.getWorktrees(); if (state.flags == null) { state.flags = []; @@ -895,7 +895,7 @@ export class WorktreeGitCommand extends QuickCommand { } } - await state.repo.deleteWorktree(uri, { force: force }); + await state.repo.git.deleteWorktree(uri, { force: force }); if (deleteBranches && worktree?.branch) { branchesToDelete.push(getReferenceFromBranch(worktree?.branch)); } @@ -1012,7 +1012,7 @@ export class WorktreeGitCommand extends QuickCommand { while (this.canStepsContinue(state)) { if (state.counter < 3 || state.worktree == null) { context.title = getTitle(state.subcommand); - context.worktrees ??= await state.repo.getWorktrees(); + context.worktrees ??= await state.repo.git.getWorktrees(); const result = yield* pickWorktreeStep(state, context, { excludeOpened: true, @@ -1114,7 +1114,7 @@ export class WorktreeGitCommand extends QuickCommand { context.title = state?.overrides?.title ?? getTitle(state.subcommand); if (state.counter < 3 || state.worktree == null) { - context.worktrees ??= await state.repo.getWorktrees(); + context.worktrees ??= await state.repo.git.getWorktrees(); let placeholder; switch (state.changes.type) { diff --git a/src/commands/openAssociatedPullRequestOnRemote.ts b/src/commands/openAssociatedPullRequestOnRemote.ts index 5910371a3db4c..22b9f5ba3cc1a 100644 --- a/src/commands/openAssociatedPullRequestOnRemote.ts +++ b/src/commands/openAssociatedPullRequestOnRemote.ts @@ -40,7 +40,7 @@ export class OpenAssociatedPullRequestOnRemoteCommand extends ActiveEditorComman }); if (repo == null) return; - const branch = await repo?.getBranch(); + const branch = await repo?.git.getBranch(); const pr = await branch?.getAssociatedPullRequest({ expiryOverride: true }); args = diff --git a/src/commands/openChangedFiles.ts b/src/commands/openChangedFiles.ts index b536d82a1099e..b85df44be40e6 100644 --- a/src/commands/openChangedFiles.ts +++ b/src/commands/openChangedFiles.ts @@ -28,7 +28,7 @@ export class OpenChangedFilesCommand extends Command { const repository = await getRepositoryOrShowPicker('Open All Changed Files'); if (repository == null) return; - const status = await this.container.git.getStatusForRepo(repository.uri); + const status = await this.container.git.getStatus(repository.uri); if (status == null) { void window.showWarningMessage('Unable to open changed files'); diff --git a/src/commands/openCurrentBranchOnRemote.ts b/src/commands/openCurrentBranchOnRemote.ts index 8b575a474fcb1..924b1c08f9cf9 100644 --- a/src/commands/openCurrentBranchOnRemote.ts +++ b/src/commands/openCurrentBranchOnRemote.ts @@ -25,7 +25,7 @@ export class OpenCurrentBranchOnRemoteCommand extends ActiveEditorCommand { if (repository == null) return; try { - const branch = await repository.getBranch(); + const branch = await repository.git.getBranch(); if (branch?.name) { void (await executeCommand(Commands.OpenOnRemote, { resource: { diff --git a/src/commands/openFileAtRevision.ts b/src/commands/openFileAtRevision.ts index 2796824a457b2..ae7ff5b66f7e9 100644 --- a/src/commands/openFileAtRevision.ts +++ b/src/commands/openFileAtRevision.ts @@ -142,7 +142,7 @@ export class OpenFileAtRevisionCommand extends ActiveEditorCommand { getState: async () => { const items: (CommandQuickPickItem | DirectiveQuickPickItem)[] = []; - const status = await this.container.git.getStatusForRepo(gitUri.repoPath); + const status = await this.container.git.getStatus(gitUri.repoPath); if (status != null) { for (const f of status.files) { if (f.workingTreeStatus === '?' || f.workingTreeStatus === '!') { diff --git a/src/commands/openOnlyChangedFiles.ts b/src/commands/openOnlyChangedFiles.ts index 59c8ab39d8c97..37e703ea41441 100644 --- a/src/commands/openOnlyChangedFiles.ts +++ b/src/commands/openOnlyChangedFiles.ts @@ -29,7 +29,7 @@ export class OpenOnlyChangedFilesCommand extends Command { const repository = await getRepositoryOrShowPicker('Open Changed & Close Unchanged Files'); if (repository == null) return; - const status = await this.container.git.getStatusForRepo(repository.uri); + const status = await this.container.git.getStatus(repository.uri); if (status == null) { void window.showWarningMessage('Unable to open changed & close unchanged files'); diff --git a/src/commands/quickCommand.steps.ts b/src/commands/quickCommand.steps.ts index 6012dbe6728cb..aba53342f2cc4 100644 --- a/src/commands/quickCommand.steps.ts +++ b/src/commands/quickCommand.steps.ts @@ -195,16 +195,17 @@ export async function getRemotes( ): Promise { if (repo == null) return []; - const remotes = (await repo.getRemotes(options?.filter != null ? { filter: options.filter } : undefined)).map(r => - createRemoteQuickPickItem( - r, - options?.picked != null && - (typeof options.picked === 'string' ? r.name === options.picked : options.picked.includes(r.name)), - { - buttons: options?.buttons, - upstream: true, - }, - ), + const remotes = (await repo.git.getRemotes(options?.filter != null ? { filter: options.filter } : undefined)).map( + r => + createRemoteQuickPickItem( + r, + options?.picked != null && + (typeof options.picked === 'string' ? r.name === options.picked : options.picked.includes(r.name)), + { + buttons: options?.buttons, + upstream: true, + }, + ), ); return remotes; } @@ -242,7 +243,8 @@ export async function getWorktrees( picked?: string | string[]; }, ): Promise { - const worktrees = repoOrWorktrees instanceof Repository ? await repoOrWorktrees.getWorktrees() : repoOrWorktrees; + const worktrees = + repoOrWorktrees instanceof Repository ? await repoOrWorktrees.git.getWorktrees() : repoOrWorktrees; const items = await filterMapAsync(worktrees, async w => { if ((excludeOpened && w.opened) || filter?.(w) === false) return undefined; @@ -306,12 +308,12 @@ export async function getBranchesAndOrTags( const [worktreesByBranchResult, branchesResult, tagsResult] = await Promise.allSettled([ include.includes('branches') ? getWorktreesByBranch(repo) : undefined, include.includes('branches') - ? repo.getBranches({ + ? repo.git.getBranches({ filter: filter?.branches, sort: typeof sort === 'boolean' ? sort : sort?.branches, }) : undefined, - include.includes('tags') ? repo.getTags({ filter: filter?.tags, sort: true }) : undefined, + include.includes('tags') ? repo.git.getTags({ filter: filter?.tags, sort: true }) : undefined, ]); worktreesByBranch = getSettledValue(worktreesByBranchResult); @@ -324,7 +326,7 @@ export async function getBranchesAndOrTags( include.includes('branches') ? Promise.allSettled( repos.map(r => - r.getBranches({ + r.git.getBranches({ filter: filter?.branches, sort: typeof sort === 'boolean' ? sort : sort?.branches, }), @@ -334,7 +336,10 @@ export async function getBranchesAndOrTags( include.includes('tags') ? Promise.allSettled( repos.map(r => - r.getTags({ filter: filter?.tags, sort: typeof sort === 'boolean' ? sort : sort?.tags }), + r.git.getTags({ + filter: filter?.tags, + sort: typeof sort === 'boolean' ? sort : sort?.tags, + }), ), ) : undefined, @@ -567,7 +572,7 @@ export async function* inputBranchNameStep< return [false, `'${value}' isn't a valid branch name`]; } - const alreadyExists = await state.repo.getBranch(value); + const alreadyExists = await state.repo.git.getBranch(value); if (alreadyExists) { return [false, `A branch named '${value}' already exists`]; } @@ -583,7 +588,7 @@ export async function* inputBranchNameStep< return [false, `'${value}' isn't a valid branch name`]; } - const alreadyExists = await repo.getBranch(value); + const alreadyExists = await repo.git.getBranch(value); if (alreadyExists) { return [false, `A branch named '${value}' already exists`]; } @@ -624,7 +629,7 @@ export async function* inputRemoteNameStep< if (!valid) return [false, `'${value}' isn't a valid remote name`]; if ('repo' in state) { - const alreadyExists = (await state.repo.getRemotes({ filter: r => r.name === value })).length !== 0; + const alreadyExists = (await state.repo.git.getRemotes({ filter: r => r.name === value })).length !== 0; if (alreadyExists) { return [false, `A remote named '${value}' already exists`]; } diff --git a/src/commands/remoteProviders.ts b/src/commands/remoteProviders.ts index e9e0edee75c71..21dc6dd9b0218 100644 --- a/src/commands/remoteProviders.ts +++ b/src/commands/remoteProviders.ts @@ -54,7 +54,7 @@ export class ConnectRemoteProviderCommand extends Command { const repos = new Map>(); for (const repo of this.container.git.openRepositories) { - const remote = await repo.getBestRemoteWithIntegration({ includeDisconnected: true }); + const remote = await repo.git.getBestRemoteWithIntegration({ includeDisconnected: true }); if (remote?.provider != null) { repos.set(repo, remote); } @@ -149,7 +149,7 @@ export class DisconnectRemoteProviderCommand extends Command { const repos = new Map>(); for (const repo of this.container.git.openRepositories) { - const remote = await repo.getBestRemoteWithIntegration({ includeDisconnected: false }); + const remote = await repo.git.getBestRemoteWithIntegration({ includeDisconnected: false }); if (remote != null) { repos.set(repo, remote); } diff --git a/src/commands/stashSave.ts b/src/commands/stashSave.ts index 33f5568165539..34dba97321a4a 100644 --- a/src/commands/stashSave.ts +++ b/src/commands/stashSave.ts @@ -78,7 +78,7 @@ export class StashSaveCommand extends Command { const repo = await this.container.git.getOrOpenRepository(uris[0]); args.repoPath = repo?.path; - args.onlyStaged = repo != null && hasOnlyStaged ? await repo.supports(Features.StashOnlyStaged) : false; + args.onlyStaged = repo != null && hasOnlyStaged ? await repo.git.supports(Features.StashOnlyStaged) : false; if (args.keepStaged == null && !hasStaged) { args.keepStaged = true; } @@ -117,7 +117,7 @@ export class StashSaveCommand extends Command { const repo = await this.container.git.getOrOpenRepository(uris[0]); args.repoPath = repo?.path; - args.onlyStaged = repo != null && hasOnlyStaged ? await repo.supports(Features.StashOnlyStaged) : false; + args.onlyStaged = repo != null && hasOnlyStaged ? await repo.git.supports(Features.StashOnlyStaged) : false; if (args.keepStaged == null && !hasStaged) { args.keepStaged = true; } diff --git a/src/env/node/git/localGitProvider.ts b/src/env/node/git/localGitProvider.ts index e3acc10cca753..f2376700628ee 100644 --- a/src/env/node/git/localGitProvider.ts +++ b/src/env/node/git/localGitProvider.ts @@ -273,6 +273,7 @@ export class LocalGitProvider implements GitProvider, Disposable { return this._onDidOpenRepository.event; } + private readonly _branchCache = new Map>(); private readonly _branchesCache = new Map>>(); private readonly _contributorsCache = new Map>>(); private readonly _mergeStatusCache = new Map>(); @@ -318,6 +319,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } if (e.changed(RepositoryChange.Heads, RepositoryChange.Remotes, RepositoryChangeComparisonMode.Any)) { + this._branchCache.delete(repo.path); this._branchesCache.delete(repo.path); this._contributorsCache.delete(repo.path); this._worktreesCache.delete(repo.path); @@ -332,10 +334,12 @@ export class LocalGitProvider implements GitProvider, Disposable { } if (e.changed(RepositoryChange.Merge, RepositoryChangeComparisonMode.Any)) { + this._branchCache.delete(repo.path); this._mergeStatusCache.delete(repo.path); } if (e.changed(RepositoryChange.Rebase, RepositoryChangeComparisonMode.Any)) { + this._branchCache.delete(repo.path); this._rebaseStatusCache.delete(repo.path); } @@ -1109,7 +1113,7 @@ export class LocalGitProvider implements GitProvider, Disposable { if (options?.stash) { // Stash any changes first - const status = await this.getStatusForRepo(repoPath); + const status = await this.getStatus(repoPath); if (status?.files?.length) { if (options.stash === 'prompt') { const confirm = { title: 'Stash Changes' }; @@ -1364,6 +1368,7 @@ export class LocalGitProvider implements GitProvider, Disposable { const cachesToClear = []; if (!caches.length || caches.includes('branches')) { + cachesToClear.push(this._branchCache); cachesToClear.push(this._branchesCache); } @@ -2096,43 +2101,56 @@ export class LocalGitProvider implements GitProvider, Disposable { @gate() @log() async getBranch(repoPath: string): Promise { - let { - values: [branch], - } = await this.getBranches(repoPath, { filter: b => b.current }); - if (branch != null) return branch; + let branchPromise = this.useCaching ? this._branchCache.get(repoPath) : undefined; + if (branchPromise == null) { + async function load(this: LocalGitProvider): Promise { + let { + values: [branch], + } = await this.getBranches(repoPath, { filter: b => b.current }); + if (branch != null) return branch; - const commitOrdering = configuration.get('advanced.commitOrdering'); + const commitOrdering = configuration.get('advanced.commitOrdering'); - const data = await this.git.rev_parse__currentBranch(repoPath, commitOrdering); - if (data == null) return undefined; + const data = await this.git.rev_parse__currentBranch(repoPath, commitOrdering); + if (data == null) return undefined; - const [name, upstream] = data[0].split('\n'); - if (isDetachedHead(name)) { - const [rebaseStatusResult, committerDateResult] = await Promise.allSettled([ - this.getRebaseStatus(repoPath), - this.git.log__recent_committerdate(repoPath, commitOrdering), - ]); + const [name, upstream] = data[0].split('\n'); + if (isDetachedHead(name)) { + const [rebaseStatusResult, committerDateResult] = await Promise.allSettled([ + this.getRebaseStatus(repoPath), + this.git.log__recent_committerdate(repoPath, commitOrdering), + ]); - const committerDate = getSettledValue(committerDateResult); - const rebaseStatus = getSettledValue(rebaseStatusResult); + const committerDate = getSettledValue(committerDateResult); + const rebaseStatus = getSettledValue(rebaseStatusResult); - branch = new GitBranch( - this.container, - repoPath, - rebaseStatus?.incoming.name ?? name, - false, - true, - committerDate != null ? new Date(Number(committerDate) * 1000) : undefined, - data[1], - upstream ? { name: upstream, missing: false } : undefined, - undefined, - undefined, - undefined, - rebaseStatus != null, - ); + branch = new GitBranch( + this.container, + repoPath, + rebaseStatus?.incoming.name ?? name, + false, + true, + committerDate != null ? new Date(Number(committerDate) * 1000) : undefined, + data[1], + upstream ? { name: upstream, missing: false } : undefined, + undefined, + undefined, + undefined, + rebaseStatus != null, + ); + } + + return branch; + } + + branchPromise = load.call(this); + + if (this.useCaching) { + this._branchCache.set(repoPath, branchPromise); + } } - return branch; + return branchPromise; } @log({ args: { 1: false } }) @@ -4797,7 +4815,10 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log({ args: { 1: false } }) - async getRemotes(repoPath: string | undefined, options?: { sort?: boolean }): Promise { + async getRemotes( + repoPath: string | undefined, + options?: { filter?: (remote: GitRemote) => boolean; sort?: boolean }, + ): Promise { if (repoPath == null) return []; const scope = getLogScope(); @@ -4832,7 +4853,11 @@ export class LocalGitProvider implements GitProvider, Disposable { } } - const remotes = await remotesPromise; + let remotes = await remotesPromise; + if (options?.filter != null) { + remotes = remotes.filter(options.filter); + } + if (options?.sort) { sortRemotes(remotes); } @@ -4936,7 +4961,7 @@ export class LocalGitProvider implements GitProvider, Disposable { @log() async getStatusForFile(repoPath: string, pathOrUri: string | Uri): Promise { - const status = await this.getStatusForRepo(repoPath); + const status = await this.getStatus(repoPath); if (!status?.files.length) return undefined; const [relativePath] = splitPath(pathOrUri, repoPath); @@ -4952,7 +4977,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } relativePath = relativePath.substring(0, relativePath.length - 1); - const status = await this.getStatusForRepo(repoPath); + const status = await this.getStatus(repoPath); if (!status?.files.length) return undefined; const files = status.files.filter(f => f.path.startsWith(relativePath)); @@ -4960,7 +4985,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async getStatusForRepo(repoPath: string | undefined): Promise { + async getStatus(repoPath: string | undefined): Promise { if (repoPath == null) return undefined; const porcelainVersion = (await this.git.isAtLeastVersion('2.11')) ? 2 : 1; @@ -5933,7 +5958,7 @@ export class LocalGitProvider implements GitProvider, Disposable { } @log() - async deleteWorktree(repoPath: string, path: string, options?: { force?: boolean }) { + async deleteWorktree(repoPath: string, path: string | Uri, options?: { force?: boolean }) { const scope = getLogScope(); await this.ensureGitVersion( @@ -5943,7 +5968,11 @@ export class LocalGitProvider implements GitProvider, Disposable { ); try { - await this.git.worktree__remove(repoPath, normalizePath(path), options); + await this.git.worktree__remove( + repoPath, + normalizePath(typeof path === 'string' ? path : path.fsPath), + options, + ); this.container.events.fire('git:cache:reset', { repoPath: repoPath, caches: ['worktrees'] }); } catch (ex) { Logger.error(ex, scope); diff --git a/src/git/actions/commit.ts b/src/git/actions/commit.ts index 1c7a9818b94a9..c0fd0e83ec2c3 100644 --- a/src/git/actions/commit.ts +++ b/src/git/actions/commit.ts @@ -884,7 +884,7 @@ export async function undoCommit(container: Container, commit: GitRevisionRefere return; } - const status = await container.git.getStatusForRepo(commit.repoPath); + const status = await container.git.getStatus(commit.repoPath); if (status?.files.length) { const confirm = { title: 'Undo Commit' }; const cancel = { title: 'Cancel', isCloseAffordance: true }; diff --git a/src/git/gitProvider.ts b/src/git/gitProvider.ts index f884de9173e65..5e0c74bd1d29d 100644 --- a/src/git/gitProvider.ts +++ b/src/git/gitProvider.ts @@ -112,51 +112,10 @@ export interface RepositoryVisibilityInfo { remotesHash?: string; } -export interface GitProvider extends Disposable { - get onDidChange(): Event; - get onDidChangeRepository(): Event; - get onDidCloseRepository(): Event; - get onDidOpenRepository(): Event; - - readonly descriptor: GitProviderDescriptor; - readonly supportedSchemes: Set; - - discoverRepositories( - uri: Uri, - options?: { cancellation?: CancellationToken; depth?: number; silent?: boolean }, - ): Promise; - updateContext?(): void; - openRepository( - folder: WorkspaceFolder | undefined, - uri: Uri, - root: boolean, - suspended?: boolean, - closed?: boolean, - ): Repository[]; - openRepositoryInitWatcher?(): RepositoryInitWatcher; - - supports(feature: Features): Promise; - visibility( - repoPath: string, - remotes?: GitRemote[], - ): Promise<[visibility: RepositoryVisibility, cacheKey: string | undefined]>; - - getOpenScmRepositories(): Promise; - getScmRepository(repoPath: string): Promise; - getOrOpenScmRepository(repoPath: string): Promise; - - canHandlePathOrUri(scheme: string, pathOrUri: string | Uri): string | undefined; - getAbsoluteUri(pathOrUri: string | Uri, base: string | Uri): Uri; - getBestRevisionUri(repoPath: string, path: string, ref: string | undefined): Promise; - getRelativePath(pathOrUri: string | Uri, base: string | Uri): string; - getRevisionUri(repoPath: string, path: string, ref: string): Uri; - // getRootUri(pathOrUri: string | Uri): Uri; - getWorkingUri(repoPath: string, uri: Uri): Promise; - +export interface GitProviderRepository { addRemote(repoPath: string, name: string, url: string, options?: { fetch?: boolean }): Promise; pruneRemote(repoPath: string, name: string): Promise; removeRemote(repoPath: string, name: string): Promise; - applyChangesToWorkingFile(uri: GitUri, ref1?: string, ref2?: string): Promise; applyUnreachableCommitForPatch?( repoPath: string, ref: string, @@ -172,7 +131,6 @@ export interface GitProvider extends Disposable { ref: string, options?: { createBranch?: string | undefined } | { path?: string | undefined }, ): Promise; - clone?(url: string, parentPath: string): Promise; createUnreachableCommitForPatch?( repoPath: string, contents: string, @@ -180,6 +138,7 @@ export interface GitProvider extends Disposable { message: string, ): Promise; excludeIgnoredUris(repoPath: string, uris: Uri[]): Promise; + fetch( repoPath: string, options?: { @@ -206,52 +165,7 @@ export interface GitProvider extends Disposable { publish?: { remote: string }; }, ): Promise; - findRepositoryUri(uri: Uri, isDirectory?: boolean): Promise; - getLeftRightCommitCount( - repoPath: string, - range: GitRevisionRange, - options?: { authors?: GitUser[] | undefined; excludeMerges?: boolean }, - ): Promise; - /** - * Returns the blame of a file - * @param uri Uri of the file to blame - * @param document Optional TextDocument to blame the contents of if dirty - */ - getBlame(uri: GitUri, document?: TextDocument | undefined): Promise; - /** - * Returns the blame of a file, using the editor contents (for dirty editors) - * @param uri Uri of the file to blame - * @param contents Contents from the editor to use - */ - getBlameContents(uri: GitUri, contents: string): Promise; - /** - * Returns the blame of a single line - * @param uri Uri of the file to blame - * @param editorLine Editor line number (0-based) to blame (Git is 1-based) - * @param document Optional TextDocument to blame the contents of if dirty - * @param options.forceSingleLine Forces blame to be for the single line (rather than the whole file) - */ - getBlameForLine( - uri: GitUri, - editorLine: number, - document?: TextDocument | undefined, - options?: { forceSingleLine?: boolean }, - ): Promise; - /** - * Returns the blame of a single line, using the editor contents (for dirty editors) - * @param uri Uri of the file to blame - * @param editorLine Editor line number (0-based) to blame (Git is 1-based) - * @param contents Contents from the editor to use - */ - getBlameForLineContents( - uri: GitUri, - editorLine: number, - contents: string, - options?: { forceSingleLine?: boolean }, - ): Promise; - getBlameForRange(uri: GitUri, range: Range): Promise; - getBlameForRangeContents(uri: GitUri, range: Range, contents: string): Promise; - getBlameRange(blame: GitBlame, uri: GitUri, range: Range): GitBlameLines | undefined; + getBranch(repoPath: string): Promise; getBranches( repoPath: string, @@ -319,33 +233,6 @@ export interface GitProvider extends Disposable { options?: { context?: number; uris?: Uri[] }, ): Promise; getDiffFiles?(repoPath: string | Uri, contents: string): Promise; - /** - * Returns a file diff between two commits - * @param uri Uri of the file to diff - * @param ref1 Commit to diff from - * @param ref2 Commit to diff to - */ - getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise; - /** - * Returns a file diff between a commit and the specified contents - * @param uri Uri of the file to diff - * @param ref Commit to diff from - * @param contents Contents to use for the diff - */ - getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise; - /** - * Returns a line diff between two commits - * @param uri Uri of the file to diff - * @param editorLine Editor line number (0-based) to blame (Git is 1-based) - * @param ref1 Commit to diff from - * @param ref2 Commit to diff to - */ - getDiffForLine( - uri: GitUri, - editorLine: number, - ref1: string | undefined, - ref2?: string, - ): Promise; getDiffStatus( repoPath: string, ref1OrRange: string | GitRevisionRange, @@ -356,6 +243,11 @@ export interface GitProvider extends Disposable { getFirstCommitSha?(repoPath: string): Promise; getGitDir?(repoPath: string): Promise; getLastFetchedTimestamp(repoPath: string): Promise; + getLeftRightCommitCount( + repoPath: string, + range: GitRevisionRange, + options?: { authors?: GitUser[] | undefined; excludeMerges?: boolean }, + ): Promise; getLog( repoPath: string, options?: { @@ -436,12 +328,15 @@ export interface GitProvider extends Disposable { skip?: number | undefined; }, ): Promise; - getRemotes(repoPath: string | undefined, options?: { sort?: boolean }): Promise; + getRemotes( + repoPath: string | undefined, + options?: { filter?: (remote: GitRemote) => boolean; sort?: boolean }, + ): Promise; getRevisionContent(repoPath: string, path: string, ref: string): Promise; getStash(repoPath: string | undefined): Promise; + getStatus(repoPath: string | undefined): Promise; getStatusForFile(repoPath: string, uri: Uri): Promise; getStatusForFiles(repoPath: string, pathOrGlob: Uri): Promise; - getStatusForRepo(repoPath: string | undefined): Promise; getTags( repoPath: string | undefined, options?: { @@ -462,10 +357,7 @@ export interface GitProvider extends Disposable { ): Promise; hasCommitBeenPushed(repoPath: string, ref: string): Promise; - hasUnsafeRepositories?(): boolean; isAncestorOf(repoPath: string, ref1: string, ref2: string): Promise; - isTrackable(uri: Uri): boolean; - isTracked(uri: Uri): Promise; getDiffTool(repoPath?: string): Promise; openDiffTool( @@ -539,7 +431,123 @@ export interface GitProvider extends Disposable { ): Promise; getWorktrees?(repoPath: string): Promise; getWorktreesDefaultUri?(repoPath: string): Promise; - deleteWorktree?(repoPath: string, path: string, options?: { force?: boolean }): Promise; + deleteWorktree?(repoPath: string, path: string | Uri, options?: { force?: boolean }): Promise; +} + +export interface GitProvider extends GitProviderRepository, Disposable { + get onDidChange(): Event; + get onDidChangeRepository(): Event; + get onDidCloseRepository(): Event; + get onDidOpenRepository(): Event; + + readonly descriptor: GitProviderDescriptor; + readonly supportedSchemes: Set; + + discoverRepositories( + uri: Uri, + options?: { cancellation?: CancellationToken; depth?: number; silent?: boolean }, + ): Promise; + updateContext?(): void; + openRepository( + folder: WorkspaceFolder | undefined, + uri: Uri, + root: boolean, + suspended?: boolean, + closed?: boolean, + ): Repository[]; + openRepositoryInitWatcher?(): RepositoryInitWatcher; + + supports(feature: Features): Promise; + visibility( + repoPath: string, + remotes?: GitRemote[], + ): Promise<[visibility: RepositoryVisibility, cacheKey: string | undefined]>; + + getOpenScmRepositories(): Promise; + getScmRepository(repoPath: string): Promise; + getOrOpenScmRepository(repoPath: string): Promise; + + canHandlePathOrUri(scheme: string, pathOrUri: string | Uri): string | undefined; + findRepositoryUri(uri: Uri, isDirectory?: boolean): Promise; + getAbsoluteUri(pathOrUri: string | Uri, base: string | Uri): Uri; + getBestRevisionUri(repoPath: string, path: string, ref: string | undefined): Promise; + getRelativePath(pathOrUri: string | Uri, base: string | Uri): string; + getRevisionUri(repoPath: string, path: string, ref: string): Uri; + // getRootUri(pathOrUri: string | Uri): Uri; + getWorkingUri(repoPath: string, uri: Uri): Promise; + + applyChangesToWorkingFile(uri: GitUri, ref1?: string, ref2?: string): Promise; + clone?(url: string, parentPath: string): Promise; + /** + * Returns the blame of a file + * @param uri Uri of the file to blame + * @param document Optional TextDocument to blame the contents of if dirty + */ + getBlame(uri: GitUri, document?: TextDocument | undefined): Promise; + /** + * Returns the blame of a file, using the editor contents (for dirty editors) + * @param uri Uri of the file to blame + * @param contents Contents from the editor to use + */ + getBlameContents(uri: GitUri, contents: string): Promise; + /** + * Returns the blame of a single line + * @param uri Uri of the file to blame + * @param editorLine Editor line number (0-based) to blame (Git is 1-based) + * @param document Optional TextDocument to blame the contents of if dirty + * @param options.forceSingleLine Forces blame to be for the single line (rather than the whole file) + */ + getBlameForLine( + uri: GitUri, + editorLine: number, + document?: TextDocument | undefined, + options?: { forceSingleLine?: boolean }, + ): Promise; + /** + * Returns the blame of a single line, using the editor contents (for dirty editors) + * @param uri Uri of the file to blame + * @param editorLine Editor line number (0-based) to blame (Git is 1-based) + * @param contents Contents from the editor to use + */ + getBlameForLineContents( + uri: GitUri, + editorLine: number, + contents: string, + options?: { forceSingleLine?: boolean }, + ): Promise; + getBlameForRange(uri: GitUri, range: Range): Promise; + getBlameForRangeContents(uri: GitUri, range: Range, contents: string): Promise; + getBlameRange(blame: GitBlame, uri: GitUri, range: Range): GitBlameLines | undefined; + /** + * Returns a file diff between two commits + * @param uri Uri of the file to diff + * @param ref1 Commit to diff from + * @param ref2 Commit to diff to + */ + getDiffForFile(uri: GitUri, ref1: string | undefined, ref2?: string): Promise; + /** + * Returns a file diff between a commit and the specified contents + * @param uri Uri of the file to diff + * @param ref Commit to diff from + * @param contents Contents to use for the diff + */ + getDiffForFileContents(uri: GitUri, ref: string, contents: string): Promise; + /** + * Returns a line diff between two commits + * @param uri Uri of the file to diff + * @param editorLine Editor line number (0-based) to blame (Git is 1-based) + * @param ref1 Commit to diff from + * @param ref2 Commit to diff to + */ + getDiffForLine( + uri: GitUri, + editorLine: number, + ref1: string | undefined, + ref2?: string, + ): Promise; + hasUnsafeRepositories?(): boolean; + isTrackable(uri: Uri): boolean; + isTracked(uri: Uri): Promise; } export interface RevisionUriData { diff --git a/src/git/gitProviderService.ts b/src/git/gitProviderService.ts index fe6a6c071cb08..382253d624719 100644 --- a/src/git/gitProviderService.ts +++ b/src/git/gitProviderService.ts @@ -183,7 +183,7 @@ export class GitProviderService implements Disposable { for (const repo of added) { const remoteProviders = new Set(); - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { remoteProviders.add(remote.provider?.id ?? 'unknown'); } @@ -1101,7 +1101,7 @@ export class GitProviderService implements Disposable { let hasSupportedIntegration = false; let hasConnectedIntegration = false; - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { remoteProviders.add(remote.provider?.id ?? 'unknown'); reposWithRemotes.add(repo.uri.toString()); @@ -1563,7 +1563,14 @@ export class GitProviderService implements Disposable { } @log() - async getBranch(repoPath: string | Uri | undefined): Promise { + async getBranch(repoPath: string | Uri | undefined, name?: string): Promise { + if (name != null) { + const { + values: [branch], + } = await this.getBranches(repoPath, { filter: b => b.name === name }); + return branch; + } + if (repoPath == null) return undefined; const { provider, path } = this.getProvider(repoPath); @@ -2171,10 +2178,23 @@ export class GitProviderService implements Disposable { return undefined; } + @log() + async getRemote( + repoPath: string | Uri, + name: string, + _cancellation?: CancellationToken, + ): Promise { + if (repoPath == null) return undefined; + + const { provider, path } = this.getProvider(repoPath); + const remotes = await provider.getRemotes(path); + return remotes.find(r => r.name === name); + } + @log() async getRemotes( repoPath: string | Uri, - options?: { sort?: boolean }, + options?: { filter?: (remote: GitRemote) => boolean; sort?: boolean }, _cancellation?: CancellationToken, ): Promise { if (repoPath == null) return []; @@ -2410,7 +2430,7 @@ export class GitProviderService implements Disposable { options?: { validate?: boolean }, ): Promise<{ uri: Uri; startLine?: number; endLine?: number } | undefined> { for (const repo of this.openRepositories) { - for (const remote of await repo.getRemotes()) { + for (const remote of await repo.git.getRemotes()) { const local = await remote?.provider?.getLocalInfoFromRemoteUri(repo, uri, options); if (local != null) return local; } @@ -2428,6 +2448,14 @@ export class GitProviderService implements Disposable { return provider.getStash(path); } + @log() + async getStatus(repoPath: string | Uri | undefined): Promise { + if (repoPath == null) return undefined; + + const { provider, path } = this.getProvider(repoPath); + return provider.getStatus(path); + } + @log() async getStatusForFile(repoPath: string | Uri, uri: Uri): Promise { const { provider, path } = this.getProvider(repoPath); @@ -2441,11 +2469,11 @@ export class GitProviderService implements Disposable { } @log() - async getStatusForRepo(repoPath: string | Uri | undefined): Promise { - if (repoPath == null) return undefined; - - const { provider, path } = this.getProvider(repoPath); - return provider.getStatusForRepo(path); + async getTag(repoPath: string | Uri | undefined, name: string): Promise { + const { + values: [tag], + } = await this.getTags(repoPath, { filter: t => t.name === name }); + return tag; } @log({ args: { 1: false } }) @@ -2526,26 +2554,6 @@ export class GitProviderService implements Disposable { return provider.hasCommitBeenPushed(path, ref); } - @log({ exit: true }) - async hasRemotes(repoPath: string | Uri | undefined): Promise { - if (repoPath == null) return false; - - const repository = this.getRepository(repoPath); - if (repository == null) return false; - - return repository.hasRemotes(); - } - - @log({ exit: true }) - async hasTrackingBranch(repoPath: string | undefined): Promise { - if (repoPath == null) return false; - - const repository = this.getRepository(repoPath); - if (repository == null) return false; - - return repository.hasUpstreamBranch(); - } - @log({ exit: true }) hasUnsafeRepositories(): boolean { for (const provider of this._providers.values()) { @@ -2825,7 +2833,7 @@ export class GitProviderService implements Disposable { } @log() - deleteWorktree(repoPath: string | Uri, path: string, options?: { force?: boolean }): Promise { + deleteWorktree(repoPath: string | Uri, path: string | Uri, options?: { force?: boolean }): Promise { const { provider, path: rp } = this.getProvider(repoPath); return Promise.resolve(provider.deleteWorktree?.(rp, path, options)); } diff --git a/src/git/models/branch.ts b/src/git/models/branch.ts index f13e1e4a05275..2053d0ef51d0d 100644 --- a/src/git/models/branch.ts +++ b/src/git/models/branch.ts @@ -267,9 +267,7 @@ export async function getTargetBranchName( if (options?.cancellation?.isCancellationRequested) return { value: undefined, paused: false }; if (targetBase != null) { - const [targetBranch] = ( - await container.git.getBranches(branch.repoPath, { filter: b => b.name === targetBase }) - ).values; + const targetBranch = await container.git.getBranch(branch.repoPath, targetBase); if (targetBranch != null) return { value: targetBranch.name, paused: false }; } @@ -385,7 +383,7 @@ export async function getLocalBranchByUpstream( qualifiedRemoteBranchName = `remotes/${remoteBranchName}`; } - branches ??= new PageableResult(p => repo.getBranches(p != null ? { paging: p } : undefined)); + branches ??= new PageableResult(p => repo.git.getBranches(p != null ? { paging: p } : undefined)); for await (const branch of branches.values()) { if ( !branch.remote && diff --git a/src/git/models/commit.ts b/src/git/models/commit.ts index 30cc2b8832f11..6966f97301578 100644 --- a/src/git/models/commit.ts +++ b/src/git/models/commit.ts @@ -209,7 +209,7 @@ export class GitCommit implements GitRevisionReference { this._etagFileSystem = repository?.etagFileSystem; if (this._etagFileSystem != null) { - const status = await this.container.git.getStatusForRepo(this.repoPath); + const status = await this.container.git.getStatus(this.repoPath); if (status != null) { this._files = status.files.flatMap(f => f.getPseudoFileChanges()); } diff --git a/src/git/models/pullRequest.ts b/src/git/models/pullRequest.ts index d0370474069f4..9496d787bd82a 100644 --- a/src/git/models/pullRequest.ts +++ b/src/git/models/pullRequest.ts @@ -377,7 +377,7 @@ export async function ensurePullRequestRemote( const prRemoteUrl = identity.remote.url.replace(/\.git$/, ''); let found = false; - for (const remote of await repo.getRemotes()) { + for (const remote of await repo.git.getRemotes()) { if (remote.matches(prRemoteUrl)) { found = true; break; diff --git a/src/git/models/repository.ts b/src/git/models/repository.ts index 3eac4a2e1e290..1b8ad41c087a3 100644 --- a/src/git/models/repository.ts +++ b/src/git/models/repository.ts @@ -1,19 +1,18 @@ import { md5, uuid } from '@env/crypto'; -import type { CancellationToken, ConfigurationChangeEvent, Event, Uri, WorkspaceFolder } from 'vscode'; +import type { ConfigurationChangeEvent, Event, Uri, WorkspaceFolder } from 'vscode'; import { Disposable, EventEmitter, ProgressLocation, RelativePattern, window, workspace } from 'vscode'; import type { CreatePullRequestActionContext } from '../../api/gitlens'; import type { RepositoriesSorting } from '../../config'; import { Schemes } from '../../constants'; -import type { SearchQuery } from '../../constants.search'; import type { Container } from '../../container'; -import type { FeatureAccess, Features, PlusFeatures } from '../../features'; +import type { FeatureAccess, PlusFeatures } from '../../features'; import { showCreatePullRequestPrompt, showGenericErrorMessage } from '../../messages'; -import type { HostingIntegration } from '../../plus/integrations/integration'; import type { RepoComparisonKey } from '../../repositories'; import { asRepoComparisonKey } from '../../repositories'; import { formatDate, fromNow } from '../../system/date'; import { gate } from '../../system/decorators/gate'; import { debug, log, logName } from '../../system/decorators/log'; +import { memoize } from '../../system/decorators/memoize'; import type { Deferrable } from '../../system/function'; import { debounce } from '../../system/function'; import { filter, groupByMap, join, map, min, some } from '../../system/iterable'; @@ -24,31 +23,34 @@ import { basename, normalizePath } from '../../system/path'; import { sortCompare } from '../../system/string'; import { executeActionCommand } from '../../system/vscode/command'; import { configuration } from '../../system/vscode/configuration'; -import type { GitDir, GitProviderDescriptor, GitRepositoryCaches, PagingOptions } from '../gitProvider'; -import type { RemoteProvider } from '../remotes/remoteProvider'; -import type { GitSearch } from '../search'; -import type { BranchSortOptions, GitBranch } from './branch'; +import type { GitProviderDescriptor, GitProviderRepository } from '../gitProvider'; +import type { GitProviderService } from '../gitProviderService'; +import type { GitBranch } from './branch'; import { getBranchNameWithoutRemote, getRemoteNameFromBranchName } from './branch'; -import type { GitCommit } from './commit'; -import type { GitContributor } from './contributor'; -import type { GitDiffShortStat } from './diff'; -import type { GitLog } from './log'; -import type { GitMergeStatus } from './merge'; -import type { GitRebaseStatus } from './rebase'; import type { GitBranchReference, GitReference, GitTagReference } from './reference'; import { getNameWithoutRemote, isBranchReference } from './reference'; import type { GitRemote } from './remote'; -import type { GitStash } from './stash'; -import type { GitStatus } from './status'; -import type { GitTag, TagSortOptions } from './tag'; import type { GitWorktree } from './worktree'; +type RemoveFirstArg = F extends (first: any, ...args: infer P) => infer R ? (...args: P) => R : never; + +export type RepoGitProviderService = Pick< + { + [K in keyof GitProviderService]: RemoveFirstArg; + }, + | keyof GitProviderRepository + | 'getBestRemoteWithIntegration' + | 'getBranch' + | 'getRemote' + | 'getTag' + | 'getWorktree' + | 'supports' +>; + export interface RepositoriesSortOptions { orderBy?: RepositoriesSorting; } -const emptyArray = Object.freeze([]) as unknown as any[]; - const millisecondsPerMinute = 60 * 1000; const millisecondsPerHour = 60 * 60 * 1000; const millisecondsPerDay = 24 * 60 * 60 * 1000; @@ -221,7 +223,6 @@ export class Repository implements Disposable { } get formattedName(): string { - // return this.isMaybeWorktree() === true ? `${this.name} (worktree)` : this.name; return this.name; } @@ -241,7 +242,6 @@ export class Repository implements Disposable { return this._idHash; } - private _branch: Promise | undefined; private readonly _disposable: Disposable; private _fireChangeDebounced: Deferrable<() => void> | undefined = undefined; private _fireFileSystemChangeDebounced: Deferrable<() => void> | undefined = undefined; @@ -278,7 +278,7 @@ export class Repository implements Disposable { } // Update the name if it is a worktree - void this.getGitDir().then(gd => { + void this.git.getGitDir().then(gd => { if (gd?.commonUri == null) return; let path = gd.commonUri.path; @@ -342,8 +342,6 @@ export class Repository implements Disposable { disposables.push( this.container.events.on('git:cache:reset', e => { if (!e.data.repoPath || e.data.repoPath === this.path) { - this.resetCaches(...(e.data.caches ?? emptyArray)); - if (e.data.caches?.includes('providers')) { this.fireChange(RepositoryChange.RemoteProviders); } @@ -373,7 +371,7 @@ export class Repository implements Disposable { return watcher; } - const gitDir = await this.getGitDir(); + const gitDir = await this.git.getGitDir(); if (gitDir != null) { if (gitDir?.commonUri == null) { watch.call(this, gitDir.uri, dotGitWatcherGlobCombined); @@ -396,18 +394,42 @@ export class Repository implements Disposable { return getLoggableName(this); } - get virtual(): boolean { - return this.provider.virtual; + private _closed: boolean = false; + get closed(): boolean { + return this._closed; } - - get path(): string { - return this.uri.scheme === Schemes.File ? normalizePath(this.uri.fsPath) : this.uri.toString(); + set closed(value: boolean) { + const changed = this._closed !== value; + this._closed = value; + if (changed) { + Logger.debug(`Repository(${this.id}).closed(${value})`); + this.fireChange(this._closed ? RepositoryChange.Closed : RepositoryChange.Opened); + } } get etag(): number { return this._updatedAt; } + @memoize() + get git(): RepoGitProviderService { + const uri = this.uri; + return new Proxy(this.container.git, { + get: (target, prop: keyof GitProviderService): any => { + const value = target[prop]; + if (typeof value === 'function') { + // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-function-type + return (...args: any[]) => (value as Function).call(target, uri, ...args); + } + return value; + }, + }) as unknown as RepoGitProviderService; + } + + get path(): string { + return this.uri.scheme === Schemes.File ? normalizePath(this.uri.fsPath) : this.uri.toString(); + } + private _orderByLastFetched = false; get orderByLastFetched(): boolean { return this._orderByLastFetched; @@ -418,13 +440,16 @@ export class Repository implements Disposable { return this._updatedAt; } + get virtual(): boolean { + return this.provider.virtual; + } + private onConfigurationChanged(e?: ConfigurationChangeEvent) { if (configuration.changed(e, 'sortRepositoriesBy')) { this._orderByLastFetched = configuration.get('sortRepositoriesBy')?.startsWith('lastFetched:') ?? false; } if (e != null && configuration.changed(e, 'remotes', this.folder?.uri)) { - this.resetCaches('remotes'); this.fireChange(RepositoryChange.Remotes); } } @@ -465,7 +490,6 @@ export class Repository implements Disposable { if (match != null) { switch (match[1]) { case 'config': - this.resetCaches(); this.fireChange(RepositoryChange.Config, RepositoryChange.Remotes); return; @@ -478,12 +502,10 @@ export class Repository implements Disposable { return; case 'HEAD': - this.resetCaches('branches'); this.fireChange(RepositoryChange.Head, RepositoryChange.Heads); return; case 'ORIG_HEAD': - this.resetCaches('branches'); this.fireChange(RepositoryChange.Heads); return; @@ -501,12 +523,10 @@ export class Repository implements Disposable { return; case 'refs/heads': - this.resetCaches('branches'); this.fireChange(RepositoryChange.Heads); return; case 'refs/remotes': - this.resetCaches(); this.fireChange(RepositoryChange.Remotes); return; @@ -527,46 +547,19 @@ export class Repository implements Disposable { this.fireChange(RepositoryChange.Unknown); } - private _closed: boolean = false; - get closed(): boolean { - return this._closed; - } - set closed(value: boolean) { - const changed = this._closed !== value; - this._closed = value; - if (changed) { - Logger.debug(`Repository(${this.id}).closed(${value})`); - this.fireChange(this._closed ? RepositoryChange.Closed : RepositoryChange.Opened); - } - } - @log() access(feature?: PlusFeatures): Promise { return this.container.git.access(feature, this.uri); } - @log() - supports(feature: Features): Promise { - return this.container.git.supports(this.uri, feature); - } - + // TODO: Can we remove this -- since no callers use the return value (though maybe they need that await?) @log() async addRemote(name: string, url: string, options?: { fetch?: boolean }): Promise { - await this.container.git.addRemote(this.uri, name, url, options); - const [remote] = await this.getRemotes({ filter: r => r.url === url }); + await this.git.addRemote(name, url, options); + const [remote] = await this.git.getRemotes({ filter: r => r.url === url }); return remote; } - @log() - pruneRemote(name: string): Promise { - return this.container.git.pruneRemote(this.uri, name); - } - - @log() - removeRemote(name: string): Promise { - return this.container.git.removeRemote(this.uri, name); - } - @log() branch(...args: string[]) { void this.runTerminalCommand('branch', ...args); @@ -657,7 +650,7 @@ export class Repository implements Disposable { remote?: string; }) { try { - await this.container.git.fetch(this.uri, options); + await this.git.fetch(options); this.fireChange(RepositoryChange.Unknown); } catch (ex) { @@ -666,47 +659,10 @@ export class Repository implements Disposable { } } - async getBestRemoteWithIntegration(options?: { - filter?: (remote: GitRemote, integration: HostingIntegration) => boolean; - includeDisconnected?: boolean; - }): Promise | undefined> { - return this.container.git.getBestRemoteWithIntegration(this.uri, options); - } - - async getBranch(name?: string): Promise { - if (name) { - const { - values: [branch], - } = await this.getBranches({ filter: b => b.name === name }); - return branch; - } - - if (this._branch == null) { - this._branch = this.container.git.getBranch(this.uri); - } - return this._branch; - } - - getBranches(options?: { - filter?: (b: GitBranch) => boolean; - paging?: PagingOptions; - sort?: boolean | BranchSortOptions; - }) { - return this.container.git.getBranches(this.uri, options); - } - - getChangedFilesCount(ref?: string): Promise { - return this.container.git.getChangedFilesCount(this.uri, ref); - } - - getCommit(ref: string): Promise { - return this.container.git.getCommit(this.uri, ref); - } - @gate() @log({ exit: true }) async getCommonRepository(): Promise { - const gitDir = await this.getGitDir(); + const gitDir = await this.git.getGitDir(); if (gitDir?.commonUri == null) return this; // If the repository isn't already opened, then open it as a "closed" repo (won't show up in the UI) @@ -719,7 +675,7 @@ export class Repository implements Disposable { @log({ exit: true }) async getCommonRepositoryUri(): Promise { - const gitDir = await this.getGitDir(); + const gitDir = await this.git.getGitDir(); if (gitDir?.commonUri?.path.endsWith('/.git')) { return gitDir.commonUri.with({ path: gitDir.commonUri.path.substring(0, gitDir.commonUri.path.length - 5), @@ -729,28 +685,10 @@ export class Repository implements Disposable { return gitDir?.commonUri; } - getContributors(options?: { - all?: boolean; - merges?: boolean | 'first-parent'; - ref?: string; - stats?: boolean; - }): Promise { - return this.container.git.getContributors(this.uri, options); - } - - private _gitDir: GitDir | undefined; - private _gitDirPromise: Promise | undefined; - private getGitDir(): Promise { - if (this._gitDirPromise == null) { - this._gitDirPromise = this.container.git.getGitDir(this.uri).then(gd => (this._gitDir = gd)); - } - return this._gitDirPromise; - } - private _lastFetched: number | undefined; @gate() async getLastFetched(): Promise { - const lastFetched = await this.container.git.getLastFetchedTimestamp(this.uri); + const lastFetched = await this.git.getLastFetchedTimestamp(); // If we don't get a number, assume the fetch failed, and don't update the timestamp if (lastFetched != null) { this._lastFetched = lastFetched; @@ -759,93 +697,15 @@ export class Repository implements Disposable { return this._lastFetched ?? 0; } - getMergeStatus(): Promise { - return this.container.git.getMergeStatus(this.uri); - } - - getRebaseStatus(): Promise { - return this.container.git.getRebaseStatus(this.uri); - } - - async getRemote(remote: string): Promise { - return (await this.getRemotes()).find(r => r.name === remote); - } - - async getRemotes(options?: { filter?: (remote: GitRemote) => boolean; sort?: boolean }): Promise { - const remotes = await this.container.git.getRemotes( - this.uri, - options?.sort != null ? { sort: options.sort } : undefined, - ); - return options?.filter != null ? remotes.filter(options.filter) : remotes; - } - - getStash(): Promise { - return this.container.git.getStash(this.uri); - } - - getStatus(): Promise { - return this.container.git.getStatusForRepo(this.uri); - } - - async getTag(name: string): Promise { - const { - values: [tag], - } = await this.getTags({ filter: b => b.name === name }); - return tag; - } - - getTags(options?: { filter?: (t: GitTag) => boolean; paging?: PagingOptions; sort?: boolean | TagSortOptions }) { - return this.container.git.getTags(this.uri, options); - } - + // TODO: Move to GitProviderService? @log() async createWorktree( uri: Uri, options?: { commitish?: string; createBranch?: string; detach?: boolean; force?: boolean }, ): Promise { - await this.container.git.createWorktree(this.uri, uri.fsPath, options); + await this.git.createWorktree(uri.fsPath, options); const url = uri.toString(); - return this.container.git.getWorktree(this.uri, w => w.uri.toString() === url); - } - - getWorktrees(): Promise { - return this.container.git.getWorktrees(this.uri); - } - - async getWorktreesDefaultUri(): Promise { - return this.container.git.getWorktreesDefaultUri(this.uri); - } - - deleteWorktree(uri: Uri, options?: { force?: boolean }): Promise { - return this.container.git.deleteWorktree(this.uri, uri.fsPath, options); - } - - async hasRemotes(): Promise { - const remotes = await this.getRemotes(); - return remotes?.length > 0; - } - - async hasRemoteWithIntegration(options?: { - filter?: (remote: GitRemote, integration: HostingIntegration) => boolean; - includeDisconnected?: boolean; - }): Promise { - const remote = await this.getBestRemoteWithIntegration(options); - return remote?.provider != null; - } - - async hasUpstreamBranch(): Promise { - const branch = await this.getBranch(); - return branch?.upstream != null; - } - - isMaybeWorktree(): boolean | undefined { - if (this._gitDir == null) return undefined; - - return this._gitDir.commonUri != null; - } - - async isWorktree(): Promise { - return (await this.getGitDir())?.commonUri != null; + return this.git.getWorktree(w => w.uri.toString() === url); } @log() @@ -872,10 +732,10 @@ export class Repository implements Disposable { try { const withTags = configuration.getCore('git.pullTags', this.uri); if (configuration.getCore('git.fetchOnPull', this.uri)) { - await this.container.git.fetch(this.uri); + await this.git.fetch(); } - await this.container.git.pull(this.uri, { ...options, tags: withTags }); + await this.git.pull({ ...options, tags: withTags }); this.fireChange(RepositoryChange.Unknown); } catch (ex) { @@ -888,7 +748,7 @@ export class Repository implements Disposable { if (!this.container.actionRunners.count('createPullRequest')) return; if (!(await showCreatePullRequestPrompt(branch.name))) return; - const remote = await this.getRemote(remoteName); + const remote = await this.git.getRemote(remoteName); void executeActionCommand('createPullRequest', { repoPath: this.path, @@ -939,7 +799,7 @@ export class Repository implements Disposable { private async pushCore(options?: { force?: boolean; reference?: GitReference; publish?: { remote: string } }) { try { - await this.container.git.push(this.uri, { + await this.git.push({ reference: options?.reference, force: options?.force, publish: options?.publish, @@ -969,19 +829,6 @@ export class Repository implements Disposable { void this.runTerminalCommand('reset', ...args); } - @log({ singleLine: true }) - private resetCaches(...caches: GitRepositoryCaches[]) { - if (caches.length === 0 || caches.includes('branches')) { - this._branch = undefined; - } - - // if (caches.length === 0 || caches.includes('remotes')) { - // this._remotes = undefined; - // this._remotesDisposable?.dispose(); - // this._remotesDisposable = undefined; - // } - } - resume() { if (!this._suspended) return; @@ -1003,22 +850,6 @@ export class Repository implements Disposable { void this.runTerminalCommand('revert', ...args); } - @debug() - richSearchCommits( - search: SearchQuery, - options?: { limit?: number; ordering?: 'date' | 'author-date' | 'topo'; skip?: number }, - ): Promise { - return this.container.git.richSearchCommits(this.uri, search, options); - } - - @debug() - searchCommits( - search: SearchQuery, - options?: { cancellation?: CancellationToken; limit?: number; ordering?: 'date' | 'author-date' | 'topo' }, - ): Promise { - return this.container.git.searchCommits(this.uri, search, options); - } - async setRemoteAsDefault(remote: GitRemote, value: boolean = true) { await this.container.storage.storeWorkspace('remote:default', value ? remote.name : undefined); @@ -1037,7 +868,7 @@ export class Repository implements Disposable { @gate() @log() async stashApply(stashName: string, options?: { deleteAfter?: boolean }) { - await this.container.git.stashApply(this.uri, stashName, options); + await this.git.stashApply(stashName, options); this.fireChange(RepositoryChange.Stash); } @@ -1045,7 +876,7 @@ export class Repository implements Disposable { @gate() @log() async stashDelete(stashName: string, ref?: string) { - await this.container.git.stashDelete(this.uri, stashName, ref); + await this.git.stashDelete(stashName, ref); this.fireChange(RepositoryChange.Stash); } @@ -1053,7 +884,7 @@ export class Repository implements Disposable { @gate() @log() async stashRename(stashName: string, ref: string, message: string, stashOnRef?: string) { - await this.container.git.stashRename(this.uri, stashName, ref, message, stashOnRef); + await this.git.stashRename(stashName, ref, message, stashOnRef); this.fireChange(RepositoryChange.Stash); } @@ -1065,7 +896,7 @@ export class Repository implements Disposable { uris?: Uri[], options?: { includeUntracked?: boolean; keepIndex?: boolean; onlyStaged?: boolean }, ): Promise { - await this.container.git.stashSave(this.uri, message, uris, options); + await this.git.stashSave(message, uris, options); this.fireChange(RepositoryChange.Stash); } @@ -1073,7 +904,7 @@ export class Repository implements Disposable { @gate() @log() async stashSaveSnapshot(message?: string): Promise { - await this.container.git.stashSaveSnapshot(this.uri, message); + await this.git.stashSaveSnapshot(message); this.fireChange(RepositoryChange.Stash); } @@ -1096,7 +927,7 @@ export class Repository implements Disposable { private async switchCore(ref: string, options?: { createBranch?: string }) { try { - await this.container.git.checkout(this.uri, ref, options); + await this.git.checkout(ref, options); this.fireChange(RepositoryChange.Unknown); } catch (ex) { @@ -1274,7 +1105,7 @@ export class Repository implements Disposable { this._pendingFileSystemChange = undefined; - const uris = await this.container.git.excludeIgnoredUris(this.uri, e.uris); + const uris = await this.git.excludeIgnoredUris(e.uris); if (uris.length === 0) return; if (uris.length !== e.uris.length) { @@ -1287,7 +1118,7 @@ export class Repository implements Disposable { } private async runTerminalCommand(command: string, ...args: string[]) { - await this.container.git.runGitCommandViaTerminal?.(this.uri, command, args, { execute: true }); + await this.git.runGitCommandViaTerminal?.(command, args, { execute: true }); setTimeout(() => this.fireChange(RepositoryChange.Unknown), 2500); } diff --git a/src/git/models/worktree.ts b/src/git/models/worktree.ts index 0393f34234ef8..f6c01e57ca16d 100644 --- a/src/git/models/worktree.ts +++ b/src/git/models/worktree.ts @@ -93,7 +93,7 @@ export class GitWorktree { // eslint-disable-next-line no-async-promise-executor this._statusPromise = new Promise(async (resolve, reject) => { try { - const status = await Container.instance.git.getStatusForRepo(this.uri.fsPath); + const status = await Container.instance.git.getStatus(this.uri.fsPath); this._status = status; resolve(status); } catch (ex) { @@ -228,13 +228,13 @@ export async function getWorktreeForBranch( upstreamNames = [upstreamNames]; } - worktrees ??= await repo.getWorktrees(); + worktrees ??= await repo.git.getWorktrees(); for (const worktree of worktrees) { if (worktree.branch?.name === branchName) return worktree; if (upstreamNames == null || worktree.branch == null) continue; - branches ??= new PageableResult(p => repo.getBranches(p != null ? { paging: p } : undefined)); + branches ??= new PageableResult(p => repo.git.getBranches(p != null ? { paging: p } : undefined)); for await (const branch of branches.values()) { if (branch.name === worktree.branch.name) { if ( @@ -346,7 +346,7 @@ export async function getWorktreesByBranch( if (repos == null) return worktreesByBranch; async function addWorktrees(repo: Repository) { - groupWorktreesByBranch(await repo.getWorktrees(), { + groupWorktreesByBranch(await repo.git.getWorktrees(), { includeDefault: options?.includeDefault, worktreesByBranch: worktreesByBranch, }); diff --git a/src/git/remotes/bitbucket-server.ts b/src/git/remotes/bitbucket-server.ts index 579db0e837b85..e02aa43634118 100644 --- a/src/git/remotes/bitbucket-server.ts +++ b/src/git/remotes/bitbucket-server.ts @@ -123,7 +123,7 @@ export class BitbucketServerRemote extends RemoteProvider { } while (index > 0); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { diff --git a/src/git/remotes/bitbucket.ts b/src/git/remotes/bitbucket.ts index 8736f7c3e33fa..57b199b1496c0 100644 --- a/src/git/remotes/bitbucket.ts +++ b/src/git/remotes/bitbucket.ts @@ -107,7 +107,7 @@ export class BitbucketRemote extends RemoteProvider { } while (index > 0); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { diff --git a/src/git/remotes/gerrit.ts b/src/git/remotes/gerrit.ts index f8660286236d8..0b354233557da 100644 --- a/src/git/remotes/gerrit.ts +++ b/src/git/remotes/gerrit.ts @@ -124,7 +124,7 @@ export class GerritRemote extends RemoteProvider { } while (index > 0); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { @@ -154,7 +154,7 @@ export class GerritRemote extends RemoteProvider { } while (index > 0); if (possibleTags.size !== 0) { - const { values: tags } = await repository.getTags({ + const { values: tags } = await repository.git.getTags({ filter: t => possibleTags.has(t.name), }); for (const tag of tags) { diff --git a/src/git/remotes/gitea.ts b/src/git/remotes/gitea.ts index 48ccadfeb10c9..aeeead613eab4 100644 --- a/src/git/remotes/gitea.ts +++ b/src/git/remotes/gitea.ts @@ -105,7 +105,7 @@ export class GiteaRemote extends RemoteProvider { } while (index < path.length && index !== -1); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { diff --git a/src/git/remotes/github.ts b/src/git/remotes/github.ts index 7b62466125a9b..eccb4bba64901 100644 --- a/src/git/remotes/github.ts +++ b/src/git/remotes/github.ts @@ -234,7 +234,7 @@ export class GitHubRemote extends RemoteProvider { } while (index > 0); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { diff --git a/src/git/remotes/gitlab.ts b/src/git/remotes/gitlab.ts index 826c882ed19d6..530386d485e50 100644 --- a/src/git/remotes/gitlab.ts +++ b/src/git/remotes/gitlab.ts @@ -327,7 +327,7 @@ export class GitLabRemote extends RemoteProvider { } while (index > 0); if (possibleBranches.size !== 0) { - const { values: branches } = await repository.getBranches({ + const { values: branches } = await repository.git.getBranches({ filter: b => b.remote && possibleBranches.has(b.getNameWithoutRemote()), }); for (const branch of branches) { diff --git a/src/plus/drafts/draftsService.ts b/src/plus/drafts/draftsService.ts index b1b8340c887c0..8ca54e651bd4f 100644 --- a/src/plus/drafts/draftsService.ts +++ b/src/plus/drafts/draftsService.ts @@ -754,7 +754,7 @@ export class DraftService implements Disposable { ): Promise { let integration; if (isRepository(repoOrIntegrationId)) { - const remoteProvider = await repoOrIntegrationId.getBestRemoteWithIntegration(); + const remoteProvider = await repoOrIntegrationId.git.getBestRemoteWithIntegration(); if (remoteProvider == null) return undefined; integration = await remoteProvider.getIntegration(); diff --git a/src/plus/integrations/providers/github/githubGitProvider.ts b/src/plus/integrations/providers/github/githubGitProvider.ts index 2280e2804d92e..5c2cfd586fdd1 100644 --- a/src/plus/integrations/providers/github/githubGitProvider.ts +++ b/src/plus/integrations/providers/github/githubGitProvider.ts @@ -164,6 +164,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { return this._onDidOpenRepository.event; } + private readonly _branchCache = new Map>(); private readonly _branchesCache = new Map>>(); private readonly _repoInfoCache = new Map(); private readonly _tagsCache = new Map>>(); @@ -204,6 +205,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { // this._branchesCache.delete(repo.path); // } + this._branchCache.delete(repo.path); this._branchesCache.delete(repo.path); this._tagsCache.delete(repo.path); this._repoInfoCache.delete(repo.path); @@ -472,6 +474,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { ...caches: ('branches' | 'contributors' | 'providers' | 'remotes' | 'stashes' | 'status' | 'tags')[] ) { if (caches.length === 0 || caches.includes('branches')) { + this._branchCache.delete(repoPath); this._branchesCache.delete(repoPath); } @@ -487,6 +490,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { @log({ singleLine: true }) private resetCaches(...caches: GitCaches[]): void { if (caches.length === 0 || caches.includes('branches')) { + this._branchCache.clear(); this._branchesCache.clear(); } @@ -922,40 +926,50 @@ export class GitHubGitProvider implements GitProvider, Disposable { } @log() - async getBranch(repoPath: string | undefined): Promise { - const { - values: [branch], - } = await this.getBranches(repoPath, { filter: b => b.current }); - if (branch != null) return branch; + async getBranch(repoPath: string): Promise { + let branchPromise = this._branchCache.get(repoPath); + if (branchPromise == null) { + async function load(this: GitHubGitProvider): Promise { + const { + values: [branch], + } = await this.getBranches(repoPath, { filter: b => b.current }); + if (branch != null) return branch; - try { - const { metadata } = await this.ensureRepositoryContext(repoPath!); + try { + const { metadata } = await this.ensureRepositoryContext(repoPath); - const revision = await metadata.getRevision(); - switch (revision.type) { - case HeadType.Tag: - case HeadType.Commit: - return new GitBranch( - this.container, - repoPath!, - revision.name, - false, - true, - undefined, - revision.revision, - undefined, - undefined, - undefined, - true, - ); + const revision = await metadata.getRevision(); + switch (revision.type) { + case HeadType.Tag: + case HeadType.Commit: + return new GitBranch( + this.container, + repoPath, + revision.name, + false, + true, + undefined, + revision.revision, + undefined, + undefined, + undefined, + true, + ); + } + + return undefined; + } catch (ex) { + debugger; + Logger.error(ex, getLogScope()); + return undefined; + } } - return undefined; - } catch (ex) { - debugger; - Logger.error(ex, getLogScope()); - return undefined; + branchPromise = load.call(this); + this._branchCache.set(repoPath, branchPromise); } + + return branchPromise; } @log({ args: { 1: false } }) @@ -2765,7 +2779,10 @@ export class GitHubGitProvider implements GitProvider, Disposable { } @log({ args: { 1: false } }) - async getRemotes(repoPath: string | undefined, _options?: { sort?: boolean }): Promise { + async getRemotes( + repoPath: string | undefined, + _options?: { filter?: (remote: GitRemote) => boolean; sort?: boolean }, + ): Promise { if (repoPath == null) return []; const providers = loadRemoteProviders(configuration.get('remotes', null)); @@ -2817,7 +2834,7 @@ export class GitHubGitProvider implements GitProvider, Disposable { } @log() - async getStatusForRepo(repoPath: string | undefined): Promise { + async getStatus(repoPath: string | undefined): Promise { if (repoPath == null) return undefined; const context = await this.ensureRepositoryContext(repoPath); diff --git a/src/plus/launchpad/launchpadProvider.ts b/src/plus/launchpad/launchpadProvider.ts index 09bef4d6d14e8..05c5f0e4aa884 100644 --- a/src/plus/launchpad/launchpadProvider.ts +++ b/src/plus/launchpad/launchpadProvider.ts @@ -572,7 +572,7 @@ export class LaunchpadProvider implements Disposable { async function matchRemotes(repo: Repository) { if (uniqueRemoteUrls.size === 0) return; - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { if (uniqueRemoteUrls.size === 0) return; diff --git a/src/plus/repos/repositoryIdentityService.ts b/src/plus/repos/repositoryIdentityService.ts index 158e8ddf65349..a7b3054f95f70 100644 --- a/src/plus/repos/repositoryIdentityService.ts +++ b/src/plus/repos/repositoryIdentityService.ts @@ -78,7 +78,7 @@ export class RepositoryIdentityService implements Disposable { // As a fallback, try to match using the repo id. for (const repo of this.container.git.repositories) { if (remoteDomain != null && remotePath != null) { - const matchingRemotes = await repo.getRemotes({ + const matchingRemotes = await repo.git.getRemotes({ filter: r => r.matches(remoteDomain, remotePath), }); if (matchingRemotes.length > 0) { @@ -145,7 +145,7 @@ export class RepositoryIdentityService implements Disposable { ) { const repoPath = repo.uri.fsPath; - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { const remoteUrl = remote.provider?.url({ type: RemoteResourceType.Repo }); if (remoteUrl != null) { diff --git a/src/plus/webviews/focus/focusWebview.ts b/src/plus/webviews/focus/focusWebview.ts index bb41b254b315a..ccbe3b43db5e0 100644 --- a/src/plus/webviews/focus/focusWebview.ts +++ b/src/plus/webviews/focus/focusWebview.ts @@ -309,7 +309,7 @@ export class FocusWebviewProvider implements WebviewProvider { const [, remoteDomain, remotePath] = parseGitRemoteUrl(remoteUrl); let remote: GitRemote | undefined; - [remote] = await repo.getRemotes({ filter: r => r.matches(remoteDomain, remotePath) }); + [remote] = await repo.git.getRemotes({ filter: r => r.matches(remoteDomain, remotePath) }); let remoteBranchName; if (remote != null) { remoteBranchName = `${remote.name}/${ref}`; @@ -330,7 +330,7 @@ export class FocusWebviewProvider implements WebviewProvider { fetch: true, reveal: false, }); - [remote] = await repo.getRemotes({ filter: r => r.url === remoteUrl }); + [remote] = await repo.git.getRemotes({ filter: r => r.url === remoteUrl }); if (remote == null) return; remoteBranchName = `${remote.name}/${ref}`; @@ -602,7 +602,9 @@ export class FocusWebviewProvider implements WebviewProvider { const repos = []; const disposables = []; for (const repo of this.container.git.openRepositories) { - const remoteWithIntegration = await repo.getBestRemoteWithIntegration({ includeDisconnected: true }); + const remoteWithIntegration = await repo.git.getBestRemoteWithIntegration({ + includeDisconnected: true, + }); if ( remoteWithIntegration == null || repos.findIndex(repo => repo.remote === remoteWithIntegration) > -1 @@ -687,14 +689,14 @@ export class FocusWebviewProvider implements WebviewProvider { let branches = branchesByRepo.get(entry.repoAndRemote.repo); if (branches == null) { branches = new PageableResult(paging => - entry.repoAndRemote.repo.getBranches(paging != null ? { paging: paging } : undefined), + entry.repoAndRemote.repo.git.getBranches(paging != null ? { paging: paging } : undefined), ); branchesByRepo.set(entry.repoAndRemote.repo, branches); } let worktrees = worktreesByRepo.get(entry.repoAndRemote.repo); if (worktrees == null) { - worktrees = await entry.repoAndRemote.repo.getWorktrees(); + worktrees = await entry.repoAndRemote.repo.git.getWorktrees(); worktreesByRepo.set(entry.repoAndRemote.repo, worktrees); } diff --git a/src/plus/webviews/graph/graphWebview.ts b/src/plus/webviews/graph/graphWebview.ts index 922bb62363542..e78f01d9b906d 100644 --- a/src/plus/webviews/graph/graphWebview.ts +++ b/src/plus/webviews/graph/graphWebview.ts @@ -1338,7 +1338,7 @@ export class GraphWebviewProvider implements WebviewProvider b.current); if (branch == null) { - branch = await this.repository.getBranch(); + branch = await this.repository.git.getBranch(); } if (branch != null) { pick = branch; @@ -2266,7 +2266,7 @@ export class GraphWebviewProvider implements WebviewProvider { if (this.repository == null || this.container.git.repositoryCount === 0) return undefined; - const status = await this.container.git.getStatusForRepo(this.repository.path); + const status = await this.container.git.getStatus(this.repository.path); const workingTreeStatus = status?.getDiffStatus(); return { added: workingTreeStatus?.added ?? 0, @@ -2327,7 +2327,7 @@ export class GraphWebviewProvider implements WebviewProvider('createPullRequest', { @@ -3742,7 +3742,7 @@ async function formatRepositories(repositories: Repository[]): Promise { - const remote = await r.getBestRemoteWithIntegration(); + const remote = await r.git.getBestRemoteWithIntegration(); // const integration = await remote?.getIntegration(); // const connected = integration ? integration?.maybeConnected ?? (await integration?.isConnected()) : false; diff --git a/src/plus/webviews/patchDetails/repositoryChangeset.ts b/src/plus/webviews/patchDetails/repositoryChangeset.ts index 8358d70ec69fe..98ffa06e3db48 100644 --- a/src/plus/webviews/patchDetails/repositoryChangeset.ts +++ b/src/plus/webviews/patchDetails/repositoryChangeset.ts @@ -209,7 +209,7 @@ export class RepositoryWipChangeset implements RepositoryChangeset { } private async getFiles(): Promise<{ files: Change['files'] }> { - const status = await this.container.git.getStatusForRepo(this.repository.path); + const status = await this.container.git.getStatus(this.repository.path); const files: GitFileChangeShape[] = []; if (status != null) { diff --git a/src/plus/webviews/timeline/timelineWebview.ts b/src/plus/webviews/timeline/timelineWebview.ts index 251175b0bb9fc..7f279307a6456 100644 --- a/src/plus/webviews/timeline/timelineWebview.ts +++ b/src/plus/webviews/timeline/timelineWebview.ts @@ -200,7 +200,7 @@ export class TimelineWebviewProvider implements WebviewProvider 0) { // Currently only GitHub is supported. for (const repo of options.repos) { - const repoRemotes = await repo.getRemotes({ filter: r => r.domain === 'github.com' }); + const repoRemotes = await repo.git.getRemotes({ filter: r => r.domain === 'github.com' }); if (repoRemotes.length === 0) { await window.showErrorMessage( `Only GitHub is supported for this operation. Please ensure all open repositories are hosted on GitHub.`, @@ -791,7 +791,7 @@ export class WorkspacesService implements Disposable { ): Promise { const validRepos: Repository[] = []; for (const repo of repos) { - const matchingRemotes = await repo.getRemotes({ + const matchingRemotes = await repo.git.getRemotes({ filter: r => r.provider?.id === cloudWorkspaceProviderTypeToRemoteProviderId[provider], }); if (matchingRemotes.length) { @@ -917,7 +917,7 @@ export class WorkspacesService implements Disposable { ? repoOrPath : await this.container.git.getOrOpenRepository(Uri.file(repoOrPath), { closeOnOpen: true }); if (repo == null) continue; - const remote = (await repo.getRemote('origin')) || (await repo.getRemotes())?.[0]; + const remote = (await repo.git.getRemote('origin')) || (await repo.git.getRemotes())?.[0]; const remoteDescriptor = getRemoteDescriptor(remote); if (remoteDescriptor == null) continue; repoInputs.push({ @@ -1052,7 +1052,7 @@ export class WorkspacesService implements Disposable { reposPathMap.set(normalizePath(repo.uri.fsPath.toLowerCase()), repo); if (workspace instanceof CloudWorkspace) { - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { const remoteDescriptor = getRemoteDescriptor(remote); if (remoteDescriptor == null) continue; diff --git a/src/quickpicks/contributorsPicker.ts b/src/quickpicks/contributorsPicker.ts index 94c22241ccc65..881515e212fee 100644 --- a/src/quickpicks/contributorsPicker.ts +++ b/src/quickpicks/contributorsPicker.ts @@ -78,7 +78,7 @@ export async function showContributorsPicker( quickpick.busy = true; quickpick.show(); - const contributors = await repository.getContributors(); + const contributors = await repository.git.getContributors(); if (!deferred.pending) return; const items = await Promise.all( diff --git a/src/quickpicks/items/gitWizard.ts b/src/quickpicks/items/gitWizard.ts index 415cd4585abee..3c56d6a0cef44 100644 --- a/src/quickpicks/items/gitWizard.ts +++ b/src/quickpicks/items/gitWizard.ts @@ -382,7 +382,7 @@ export async function createRepositoryQuickPickItem( ) { let repoStatus; if (options?.branch || options?.status) { - repoStatus = await repository.getStatus(); + repoStatus = await repository.git.getStatus(); } let description = ''; diff --git a/src/uris/deepLinks/deepLinkService.ts b/src/uris/deepLinks/deepLinkService.ts index 87254fdc353a1..ca8f6d8a05992 100644 --- a/src/uris/deepLinks/deepLinkService.ts +++ b/src/uris/deepLinks/deepLinkService.ts @@ -213,7 +213,7 @@ export class DeepLinkService implements Disposable { } if (remoteDomain != null && remotePath != null) { - const matchingRemotes = await repo.getRemotes({ + const matchingRemotes = await repo.git.getRemotes({ filter: r => r.matches(remoteDomain, remotePath), }); if (matchingRemotes.length > 0) { @@ -276,7 +276,7 @@ export class DeepLinkService implements Disposable { branchName = `${secondaryRemote.name}/${branchName}`; } - let branch = await repo.getBranch(branchName); + let branch = await repo.git.getBranch(branchName); if (branch != null) { return branch; } @@ -287,11 +287,11 @@ export class DeepLinkService implements Disposable { if (providerRepoInfo != null && branchName != null) { const [owner, repoName] = providerRepoInfo.split('/'); if (owner != null && repoName != null) { - const remotes = await repo.getRemotes(); + const remotes = await repo.git.getRemotes(); for (const remote of remotes) { if (remote.provider?.owner === owner) { branchName = `${remote.name}/${branchBaseName}`; - branch = await repo.getBranch(branchName); + branch = await repo.git.getBranch(branchName); if (branch != null) { return branch; } @@ -302,14 +302,14 @@ export class DeepLinkService implements Disposable { } // If the above don't work, it may still exist locally. - return repo.getBranch(targetId); + return repo.git.getBranch(targetId); } private async getCommit(targetId: string): Promise { const { repo } = this._context; if (!repo) return undefined; if (await this.container.git.validateReference(repo.path, targetId)) { - return repo.getCommit(targetId); + return repo.git.getCommit(targetId); } return undefined; @@ -317,7 +317,7 @@ export class DeepLinkService implements Disposable { private async getTag(targetId: string): Promise { const { repo } = this._context; - return repo?.getTag(targetId); + return repo?.git.getTag(targetId); } private async getShaForBranch(targetId: string): Promise { @@ -869,14 +869,16 @@ export class DeepLinkService implements Disposable { } if (remoteUrl && !remote) { - const matchingRemotes = await repo.getRemotes({ filter: r => r.url === remoteUrl }); + const matchingRemotes = await repo.git.getRemotes({ filter: r => r.url === remoteUrl }); if (matchingRemotes.length > 0) { this._context.remote = matchingRemotes[0]; } } if (secondaryRemoteUrl && !secondaryRemote) { - const matchingRemotes = await repo.getRemotes({ filter: r => r.url === secondaryRemoteUrl }); + const matchingRemotes = await repo.git.getRemotes({ + filter: r => r.url === secondaryRemoteUrl, + }); if (matchingRemotes.length > 0) { this._context.secondaryRemote = matchingRemotes[0]; } @@ -911,7 +913,7 @@ export class DeepLinkService implements Disposable { if (remoteUrl && !remote) { remoteName = await this.showAddRemotePrompt( remoteUrl, - (await repo.getRemotes()).map(r => r.name), + (await repo.git.getRemotes()).map(r => r.name), ); if (remoteName) { @@ -923,7 +925,7 @@ export class DeepLinkService implements Disposable { break; } - [this._context.remote] = await repo.getRemotes({ filter: r => r.url === remoteUrl }); + [this._context.remote] = await repo.git.getRemotes({ filter: r => r.url === remoteUrl }); if (!this._context.remote) { action = DeepLinkServiceAction.DeepLinkErrored; message = 'Failed to add remote.'; @@ -938,7 +940,7 @@ export class DeepLinkService implements Disposable { if (secondaryRemoteUrl && !secondaryRemote) { secondaryRemoteName = await this.showAddRemotePrompt( secondaryRemoteUrl, - (await repo.getRemotes()).map(r => r.name), + (await repo.git.getRemotes()).map(r => r.name), ); if (secondaryRemoteName) { @@ -950,7 +952,7 @@ export class DeepLinkService implements Disposable { break; } - [this._context.secondaryRemote] = await repo.getRemotes({ + [this._context.secondaryRemote] = await repo.git.getRemotes({ filter: r => r.url === secondaryRemoteUrl, }); if (!this._context.secondaryRemote) { @@ -1291,7 +1293,7 @@ export class DeepLinkService implements Disposable { let skipSwitch = false; if (targetType === DeepLinkType.Branch) { // Check if the branch is already checked out. If so, we are done. - const currentBranch = await repo.getBranch(); + const currentBranch = await repo.git.getBranch(); this._context.currentBranch = currentBranch?.name; const targetBranch = await this.getBranch(targetId); if ( @@ -1344,7 +1346,7 @@ export class DeepLinkService implements Disposable { new Promise(resolve => once(repo.onDidChange)(async (e: RepositoryChangeEvent) => { if (e.changed(RepositoryChange.Head, RepositoryChangeComparisonMode.Any)) { - if ((await repo.getBranch())?.name !== this._context.currentBranch) { + if ((await repo.git.getBranch())?.name !== this._context.currentBranch) { resolve(true); } else { resolve(false); diff --git a/src/views/branchesView.ts b/src/views/branchesView.ts index 48357a5cb2cfc..dec9efa007004 100644 --- a/src/views/branchesView.ts +++ b/src/views/branchesView.ts @@ -82,7 +82,7 @@ export class BranchesViewNode extends RepositoriesSubscribeableNode !b.remote }); + const branches = await child.repo.git.getBranches({ filter: b => !b.remote }); if (branches.values.length === 0) { this.view.message = 'No branches could be found.'; this.view.title = 'Branches'; diff --git a/src/views/commitsView.ts b/src/views/commitsView.ts index 7d17bbd9af2c7..1deceac700e5f 100644 --- a/src/views/commitsView.ts +++ b/src/views/commitsView.ts @@ -34,7 +34,7 @@ import { registerViewCommand } from './viewCommands'; export class CommitsRepositoryNode extends RepositoryFolderNode { async getChildren(): Promise { if (this.child == null) { - const branch = await this.repo.getBranch(); + const branch = await this.repo.git.getBranch(); if (branch == null) { this.view.message = 'No commits could be found.'; @@ -159,7 +159,7 @@ export class CommitsViewNode extends RepositoriesSubscribeableNode { this.splatted = false; - const branch = await this.repo.getBranch(); + const branch = await this.repo.git.getBranch(); const ahead = (branch?.state.ahead ?? 0) > 0; const behind = (branch?.state.behind ?? 0) > 0; diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index e0cc46053c67f..dbb67d3d4d37d 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -233,7 +233,7 @@ export class BranchNode this.getLog(), this.view.container.git.getBranchesAndTagsTipsFn(this.uri.repoPath, branch.name), this.options.showStatus && branch.current - ? this.view.container.git.getStatusForRepo(this.uri.repoPath) + ? this.view.container.git.getStatus(this.uri.repoPath) : undefined, this.options.showStatus && branch.current ? this.view.container.git.getMergeStatus(this.uri.repoPath!) @@ -281,7 +281,7 @@ export class BranchNode this, branch, mergeStatus, - status ?? (await this.view.container.git.getStatusForRepo(this.uri.repoPath)), + status ?? (await this.view.container.git.getStatus(this.uri.repoPath)), this.root, ), ); @@ -296,7 +296,7 @@ export class BranchNode this, branch, rebaseStatus, - status ?? (await this.view.container.git.getStatusForRepo(this.uri.repoPath)), + status ?? (await this.view.container.git.getStatus(this.uri.repoPath)), this.root, ), ); diff --git a/src/views/nodes/branchesNode.ts b/src/views/nodes/branchesNode.ts index 0e555992eea13..8034455e9becb 100644 --- a/src/views/nodes/branchesNode.ts +++ b/src/views/nodes/branchesNode.ts @@ -35,7 +35,7 @@ export class BranchesNode extends CacheableChildrenViewNode<'branches', ViewsWit async getChildren(): Promise { if (this.children == null) { - const branches = await this.repo.getBranches({ + const branches = await this.repo.git.getBranches({ // only show local branches filter: b => !b.remote, sort: this.view.config.showCurrentBranchOnTop @@ -89,7 +89,7 @@ export class BranchesNode extends CacheableChildrenViewNode<'branches', ViewsWit const item = new TreeItem('Branches', TreeItemCollapsibleState.Collapsed); item.id = this.id; item.contextValue = ContextValues.Branches; - if (await this.repo.hasRemotes()) { + if ((await this.repo.git.getRemotes()).length) { item.contextValue += '+remotes'; } // TODO@axosoft-ramint Temporary workaround, remove when our git commands work on closed repos. diff --git a/src/views/nodes/contributorsNode.ts b/src/views/nodes/contributorsNode.ts index 88bb5fccf36ab..de1b4fea7f18c 100644 --- a/src/views/nodes/contributorsNode.ts +++ b/src/views/nodes/contributorsNode.ts @@ -57,7 +57,7 @@ export class ContributorsNode extends CacheableChildrenViewNode< const stats = this.options?.stats ?? configuration.get('views.contributors.showStatistics'); - const contributors = await this.repo.getContributors({ + const contributors = await this.repo.git.getContributors({ all: all, merges: this.options?.showMergeCommits, ref: ref, diff --git a/src/views/nodes/fileHistoryTrackerNode.ts b/src/views/nodes/fileHistoryTrackerNode.ts index ab9e3d371b371..d46f1bdacb9b5 100644 --- a/src/views/nodes/fileHistoryTrackerNode.ts +++ b/src/views/nodes/fileHistoryTrackerNode.ts @@ -76,11 +76,7 @@ export class FileHistoryTrackerNode extends SubscribeableViewNode<'file-history- if (!commitish.sha || commitish.sha === 'HEAD') { branch = await this.view.container.git.getBranch(this.uri.repoPath); } else if (!isSha(commitish.sha)) { - ({ - values: [branch], - } = await this.view.container.git.getBranches(this.uri.repoPath, { - filter: b => b.name === commitish.sha, - })); + branch = await this.view.container.git.getBranch(this.uri.repoPath, commitish.sha); } this.child = new FileHistoryNode(fileUri, this.view, this, folder, branch); } diff --git a/src/views/nodes/lineHistoryTrackerNode.ts b/src/views/nodes/lineHistoryTrackerNode.ts index 3490268b3be5b..74d72123aa886 100644 --- a/src/views/nodes/lineHistoryTrackerNode.ts +++ b/src/views/nodes/lineHistoryTrackerNode.ts @@ -87,11 +87,7 @@ export class LineHistoryTrackerNode extends SubscribeableViewNode< if (!commitish.sha || commitish.sha === 'HEAD') { branch = await this.view.container.git.getBranch(this.uri.repoPath); } else if (!isSha(commitish.sha)) { - ({ - values: [branch], - } = await this.view.container.git.getBranches(this.uri.repoPath, { - filter: b => b.name === commitish.sha, - })); + branch = await this.view.container.git.getBranch(this.uri.repoPath, commitish.sha); } this.child = new LineHistoryNode(fileUri, this.view, this, branch, selection, editorContents); } diff --git a/src/views/nodes/remoteNode.ts b/src/views/nodes/remoteNode.ts index aea3890cdb627..cbf0f1842a394 100644 --- a/src/views/nodes/remoteNode.ts +++ b/src/views/nodes/remoteNode.ts @@ -40,7 +40,7 @@ export class RemoteNode extends ViewNode<'remote', ViewsWithRemotes> { } async getChildren(): Promise { - const branches = await this.repo.getBranches({ + const branches = await this.repo.git.getBranches({ // only show remote branches for this remote filter: b => b.remote && b.name.startsWith(this.remote.name), sort: true, diff --git a/src/views/nodes/remotesNode.ts b/src/views/nodes/remotesNode.ts index f534e8ec0d103..0dc945dd1847d 100644 --- a/src/views/nodes/remotesNode.ts +++ b/src/views/nodes/remotesNode.ts @@ -32,7 +32,7 @@ export class RemotesNode extends CacheableChildrenViewNode<'remotes', ViewsWithR async getChildren(): Promise { if (this.children == null) { - const remotes = await this.repo.getRemotes({ sort: true }); + const remotes = await this.repo.git.getRemotes({ sort: true }); if (remotes.length === 0) { return [new MessageNode(this.view, this, 'No remotes could be found')]; } diff --git a/src/views/nodes/repositoryNode.ts b/src/views/nodes/repositoryNode.ts index 5d187a0eef384..93cceb98070f8 100644 --- a/src/views/nodes/repositoryNode.ts +++ b/src/views/nodes/repositoryNode.ts @@ -55,7 +55,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit this.updateContext({ ...context, repository: this.repo }); this._uniqueId = getViewNodeId(this.type, this.context); - this._status = this.repo.getStatus(); + this._status = this.repo.git.getStatus(); } override get id(): string { @@ -175,7 +175,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit children.push(new RemotesNode(this.uri, this.view, this, this.repo)); } - if (this.view.config.showStashes && (await this.repo.supports(Features.Stashes))) { + if (this.view.config.showStashes && (await this.repo.git.supports(Features.Stashes))) { children.push(new StashesNode(this.uri, this.view, this, this.repo)); } @@ -183,7 +183,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit children.push(new TagsNode(this.uri, this.view, this, this.repo)); } - if (this.view.config.showWorktrees && (await this.repo.supports(Features.Worktrees))) { + if (this.view.config.showWorktrees && (await this.repo.git.supports(Features.Worktrees))) { children.push(new WorktreesNode(this.uri, this.view, this, this.repo)); } @@ -342,7 +342,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit super.refresh(reset); if (reset) { - this._status = this.repo.getStatus(); + this._status = this.repo.git.getStatus(); } await this.ensureSubscription(); @@ -409,7 +409,7 @@ export class RepositoryNode extends SubscribeableViewNode<'repository', ViewsWit }, }) private async onFileSystemChanged(_e: RepositoryFileSystemChangeEvent) { - this._status = this.repo.getStatus(); + this._status = this.repo.git.getStatus(); if (this.children !== undefined) { const status = await this._status; diff --git a/src/views/nodes/stashesNode.ts b/src/views/nodes/stashesNode.ts index 10b7ba0fd4bbf..48c0dba478cd1 100644 --- a/src/views/nodes/stashesNode.ts +++ b/src/views/nodes/stashesNode.ts @@ -33,7 +33,7 @@ export class StashesNode extends CacheableChildrenViewNode<'stashes', ViewsWithS async getChildren(): Promise { if (this.children == null) { - const stash = await this.repo.getStash(); + const stash = await this.repo.git.getStash(); if (stash == null) return [new MessageNode(this.view, this, 'No stashes could be found.')]; this.children = [...map(stash.commits.values(), c => new StashNode(this.view, this, c))]; diff --git a/src/views/nodes/tagsNode.ts b/src/views/nodes/tagsNode.ts index 1ed3a3875b2af..bd2a42d2f1ef5 100644 --- a/src/views/nodes/tagsNode.ts +++ b/src/views/nodes/tagsNode.ts @@ -34,7 +34,7 @@ export class TagsNode extends CacheableChildrenViewNode<'tags', ViewsWithTagsNod async getChildren(): Promise { if (this.children == null) { - const tags = await this.repo.getTags({ sort: true }); + const tags = await this.repo.git.getTags({ sort: true }); if (tags.values.length === 0) return [new MessageNode(this.view, this, 'No tags could be found.')]; // TODO@eamodio handle paging diff --git a/src/views/nodes/worktreesNode.ts b/src/views/nodes/worktreesNode.ts index c2f3d0d1a007c..16f330ebe42ff 100644 --- a/src/views/nodes/worktreesNode.ts +++ b/src/views/nodes/worktreesNode.ts @@ -40,7 +40,7 @@ export class WorktreesNode extends CacheableChildrenViewNode<'worktrees', ViewsW const access = await this.repo.access(PlusFeatures.Worktrees); if (!access.allowed) return []; - const worktrees = await this.repo.getWorktrees(); + const worktrees = await this.repo.git.getWorktrees(); if (worktrees.length === 0) return [new MessageNode(this.view, this, 'No worktrees could be found.')]; this.children = await mapAsync(sortWorktrees(worktrees), async w => { diff --git a/src/views/remotesView.ts b/src/views/remotesView.ts index 106f50b71f450..95d55b21bb227 100644 --- a/src/views/remotesView.ts +++ b/src/views/remotesView.ts @@ -74,7 +74,7 @@ export class RemotesViewNode extends RepositoriesSubscribeableNode { - const branch = await repository.getBranch(branchName); + const branch = await repository.git.getBranch(branchName); if (branch == null) return undefined; if (this.mode === 'commit') { @@ -1515,7 +1515,7 @@ export class CommitDetailsWebviewProvider } private async getWipChange(repository: Repository): Promise { - const status = await this.container.git.getStatusForRepo(repository.path); + const status = await this.container.git.getStatus(repository.path); if (status == null) return undefined; const files: GitFileChangeShape[] = [];