From a26fe3e4666aae75fdbfaacf7be153a07bdd12e8 Mon Sep 17 00:00:00 2001 From: Ladislau Szomoru <3372902+lszomoru@users.noreply.github.com> Date: Fri, 10 Jan 2025 00:20:57 +0100 Subject: [PATCH] Git - do not show "Open on GitHub" action for commits that have not been pushed to the remote (#237605) --- extensions/git/src/blame.ts | 4 +++- extensions/git/src/git.ts | 9 ++++++++ extensions/git/src/repository.ts | 30 ++++++++++++++++++++++++++ extensions/git/src/timelineProvider.ts | 4 +++- 4 files changed, 45 insertions(+), 2 deletions(-) diff --git a/extensions/git/src/blame.ts b/extensions/git/src/blame.ts index 110b4601b15f5..8ad5703bbff53 100644 --- a/extensions/git/src/blame.ts +++ b/extensions/git/src/blame.ts @@ -218,7 +218,9 @@ export class GitBlameController { // Remote commands const defaultRemote = repository.getDefaultRemote(); - if (defaultRemote?.fetchUrl) { + const unpublishedCommits = await repository.getUnpublishedCommits(); + + if (defaultRemote?.fetchUrl && !unpublishedCommits.has(blameInformation.hash)) { remoteSourceCommands.push(...await getRemoteSourceControlHistoryItemCommands(defaultRemote.fetchUrl)); } } diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index b000245a0f2ec..7e2fd062f888e 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -2848,6 +2848,15 @@ export class Repository { return commits[0]; } + async revList(ref1: string, ref2: string): Promise { + const result = await this.exec(['rev-list', `${ref1}..${ref2}`]); + if (result.stderr) { + return []; + } + + return result.stdout.trim().split('\n'); + } + async revParse(ref: string): Promise { try { const result = await fs.readFile(path.join(this.dotGit.path, ref), 'utf8'); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index c576bc790b086..9b70bef793cb5 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -841,6 +841,7 @@ export class Repository implements Disposable { private isRepositoryHuge: false | { limit: number } = false; private didWarnAboutLimit = false; + private unpublishedCommits: Set | undefined = undefined; private branchProtection = new Map(); private commitCommandCenter: CommitCommandsCenter; private resourceCommandResolver = new ResourceCommandResolver(this); @@ -2270,6 +2271,17 @@ export class Repository implements Disposable { this.isCherryPickInProgress(), this.getInputTemplate()]); + // Reset the list of unpublished commits if HEAD has + // changed (ex: checkout, fetch, pull, push, publish, etc.). + // The list of unpublished commits will be computed lazily + // on demand. + if (this.HEAD?.name !== HEAD?.name || + this.HEAD?.commit !== HEAD?.commit || + this.HEAD?.ahead !== HEAD?.ahead || + this.HEAD?.upstream !== HEAD?.upstream) { + this.unpublishedCommits = undefined; + } + this._HEAD = HEAD; this._remotes = remotes!; this._submodules = submodules!; @@ -2746,6 +2758,24 @@ export class Repository implements Disposable { return false; } + async getUnpublishedCommits(): Promise> { + if (this.unpublishedCommits) { + return this.unpublishedCommits; + } + + if (this.HEAD && this.HEAD.name && this.HEAD.upstream && this.HEAD.ahead && this.HEAD.ahead > 0) { + const ref1 = `${this.HEAD.upstream.remote}/${this.HEAD.upstream.name}`; + const ref2 = this.HEAD.name; + + const revList = await this.repository.revList(ref1, ref2); + this.unpublishedCommits = new Set(revList); + } else { + this.unpublishedCommits = new Set(); + } + + return this.unpublishedCommits; + } + dispose(): void { this.disposables = dispose(this.disposables); } diff --git a/extensions/git/src/timelineProvider.ts b/extensions/git/src/timelineProvider.ts index fbf9b139a0a63..7a4111857d9d2 100644 --- a/extensions/git/src/timelineProvider.ts +++ b/extensions/git/src/timelineProvider.ts @@ -215,6 +215,7 @@ export class GitTimelineProvider implements TimelineProvider { const openComparison = l10n.t('Open Comparison'); const defaultRemote = repo.getDefaultRemote(); + const unpublishedCommits = await repo.getUnpublishedCommits(); const remoteSourceCommands: Command[] = defaultRemote?.fetchUrl ? await getRemoteSourceControlHistoryItemCommands(defaultRemote.fetchUrl) : []; @@ -230,7 +231,8 @@ export class GitTimelineProvider implements TimelineProvider { item.description = c.authorName; } - item.setItemDetails(uri, c.hash, c.authorName!, c.authorEmail, dateFormatter.format(date), message, c.shortStat, remoteSourceCommands); + const commitRemoteSourceCommands = !unpublishedCommits.has(c.hash) ? remoteSourceCommands : []; + item.setItemDetails(uri, c.hash, c.authorName!, c.authorEmail, dateFormatter.format(date), message, c.shortStat, commitRemoteSourceCommands); const cmd = this.commands.resolveTimelineOpenDiffCommand(item, uri); if (cmd) {