diff --git a/package.json b/package.json index 9d211e7..0034e57 100644 --- a/package.json +++ b/package.json @@ -13159,7 +13159,7 @@ }, { "command": "gitlens.views.publishRepository", - "when": "!gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:none/", + "when": "!gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:(missing|none)/", "group": "inline@1" }, { @@ -13169,7 +13169,7 @@ }, { "command": "gitlens.views.publishBranch", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:none/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:(missing|none)/", "group": "inline@1" }, { @@ -13185,17 +13185,17 @@ }, { "command": "gitlens.views.fetch", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status(\\-branch)?:upstream:(?!(missing|none))/", "group": "inline@2" }, { "command": "gitlens.views.createPullRequest", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:action:createPullRequest && viewItem =~ /gitlens:status:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:action:createPullRequest && viewItem =~ /gitlens:status:upstream:(?!(missing|none))/", "group": "inline@3" }, { "command": "gitlens.openBranchOnRemote", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!(missing|none))/", "group": "inline@99", "alt": "gitlens.copyRemoteBranchUrl" }, @@ -13216,7 +13216,7 @@ }, { "command": "gitlens.views.fetch", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!(missing|none))/", "group": "1_gitlens_actions@3" }, { @@ -13231,12 +13231,12 @@ }, { "command": "gitlens.views.createPullRequest", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:action:createPullRequest && viewItem =~ /gitlens:status:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && gitlens:action:createPullRequest && viewItem =~ /gitlens:status:upstream:(?!(missing|none))/", "group": "1_gitlens_secondary_actions@3" }, { "command": "gitlens.openBranchOnRemote", - "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!none)/", + "when": "gitlens:hasRemotes && !gitlens:readonly && !gitlens:untrusted && !gitlens:hasVirtualFolders && viewItem =~ /gitlens:status:upstream:(?!(missing|none))/", "group": "2_gitlens_quickopen@1", "alt": "gitlens.copyRemoteBranchUrl" }, diff --git a/src/views/nodes/abstract/viewNode.ts b/src/views/nodes/abstract/viewNode.ts index 7d366d2..02179d1 100644 --- a/src/views/nodes/abstract/viewNode.ts +++ b/src/views/nodes/abstract/viewNode.ts @@ -52,6 +52,7 @@ export const enum ContextValues { Branches = 'gitlens:branches', BranchStatusAheadOfUpstream = 'gitlens:status-branch:upstream:ahead', BranchStatusBehindUpstream = 'gitlens:status-branch:upstream:behind', + BranchStatusMissingUpstream = 'gitlens:status-branch:upstream:missing', BranchStatusNoUpstream = 'gitlens:status-branch:upstream:none', BranchStatusSameAsUpstream = 'gitlens:status-branch:upstream:same', BranchStatusFiles = 'gitlens:status-branch:files', @@ -97,6 +98,7 @@ export const enum ContextValues { StatusFiles = 'gitlens:status:files', StatusAheadOfUpstream = 'gitlens:status:upstream:ahead', StatusBehindUpstream = 'gitlens:status:upstream:behind', + StatusMissingUpstream = 'gitlens:status:upstream:missing', StatusNoUpstream = 'gitlens:status:upstream:none', StatusSameAsUpstream = 'gitlens:status:upstream:same', Tag = 'gitlens:tag', @@ -113,7 +115,7 @@ export interface AmbientContext { readonly autolinksId?: string; readonly branch?: GitBranch; readonly branchStatus?: BranchTrackingStatus; - readonly branchStatusUpstreamType?: 'ahead' | 'behind' | 'same' | 'none'; + readonly branchStatusUpstreamType?: 'ahead' | 'behind' | 'same' | 'missing' | 'none'; readonly commit?: GitCommit; readonly comparisonId?: string; readonly comparisonFiltered?: boolean; diff --git a/src/views/nodes/branchNode.ts b/src/views/nodes/branchNode.ts index 56b690e..8424799 100644 --- a/src/views/nodes/branchNode.ts +++ b/src/views/nodes/branchNode.ts @@ -294,7 +294,11 @@ export class BranchNode }; if (branch.upstream != null) { - if (this.root && !status.state.behind && !status.state.ahead) { + if (this.root && branch.upstream.missing) { + children.push( + new BranchTrackingStatusNode(this.view, this, branch, status, 'missing', this.root), + ); + } else if (this.root && !status.state.behind && !status.state.ahead) { children.push(new BranchTrackingStatusNode(this.view, this, branch, status, 'same', this.root)); } else { if (status.state.behind) { diff --git a/src/views/nodes/branchTrackingStatusNode.ts b/src/views/nodes/branchTrackingStatusNode.ts index c946bb0..9d4ab81 100644 --- a/src/views/nodes/branchTrackingStatusNode.ts +++ b/src/views/nodes/branchTrackingStatusNode.ts @@ -1,4 +1,4 @@ -import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, window } from 'vscode'; +import { MarkdownString, ThemeColor, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri, window } from 'vscode'; import type { Colors } from '../../constants'; import { GitUri } from '../../git/gitUri'; import type { GitBranch, GitTrackingState } from '../../git/models/branch'; @@ -37,7 +37,7 @@ export class BranchTrackingStatusNode protected override readonly parent: ViewNode, public readonly branch: GitBranch, public readonly status: BranchTrackingStatus, - public readonly upstreamType: 'ahead' | 'behind' | 'same' | 'none', + public readonly upstreamType: 'ahead' | 'behind' | 'same' | 'missing' | 'none', // Specifies that the node is shown as a root public readonly root: boolean = false, private readonly options?: { @@ -65,7 +65,7 @@ export class BranchTrackingStatusNode } async getChildren(): Promise { - if (this.upstreamType === 'same' || this.upstreamType === 'none') return []; + if (this.upstreamType === 'same' || this.upstreamType === 'missing' || this.upstreamType === 'none') return []; const log = await this.getLog(); if (log == null) return []; @@ -141,7 +141,7 @@ export class BranchTrackingStatusNode async getTreeItem(): Promise { let lastFetched = 0; - if (this.upstreamType !== 'none') { + if (this.upstreamType !== 'missing' && this.upstreamType !== 'none') { const repo = this.view.container.git.getRepository(this.repoPath); lastFetched = (await repo?.getLastFetched()) ?? 0; } @@ -220,6 +220,26 @@ export class BranchTrackingStatusNode break; } + case 'missing': { + const remote = await this.branch.getRemote(); + + label = `Missing upstream branch${remote?.provider?.name ? ` on ${remote.provider.name}` : ''}`; + description = this.status.upstream; + tooltip = `Branch $(git-branch) ${this.branch.name} is missing upstream $(git-branch) ${ + this.status.upstream + }${remote?.provider?.name ? ` on ${remote.provider.name}` : ''}`; + + collapsibleState = TreeItemCollapsibleState.None; + contextValue = this.root + ? ContextValues.StatusMissingUpstream + : ContextValues.BranchStatusSameAsUpstream; + icon = new ThemeIcon( + 'warning', + new ThemeColor('gitlens.decorations.branchMissingUpstreamForegroundColor' satisfies Colors), + ); + + break; + } case 'none': { const remotes = await this.view.container.git.getRemotesWithProviders(this.branch.repoPath); const providers = GitRemote.getHighlanderProviders(remotes);