Skip to content

Commit 9fb9cb0

Browse files
committed
Adds ability to show remote branches in Branches view
- Works for the default remote only
1 parent 1c05ff7 commit 9fb9cb0

File tree

13 files changed

+216
-33
lines changed

13 files changed

+216
-33
lines changed

contributions.json

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5056,6 +5056,44 @@
50565056
]
50575057
}
50585058
},
5059+
"gitlens.views.branches.setShowRemoteBranchesOff": {
5060+
"label": "Hide Remote Branches",
5061+
"menus": {
5062+
"gitlens/views/grouped/more": [
5063+
{
5064+
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches && config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
5065+
"group": "5_gitlens",
5066+
"order": 11
5067+
}
5068+
],
5069+
"view/title": [
5070+
{
5071+
"when": "view == gitlens.views.branches && config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
5072+
"group": "5_gitlens",
5073+
"order": 11
5074+
}
5075+
]
5076+
}
5077+
},
5078+
"gitlens.views.branches.setShowRemoteBranchesOn": {
5079+
"label": "Show Remote Branches",
5080+
"menus": {
5081+
"gitlens/views/grouped/more": [
5082+
{
5083+
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches && !config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
5084+
"group": "5_gitlens",
5085+
"order": 11
5086+
}
5087+
],
5088+
"view/title": [
5089+
{
5090+
"when": "view == gitlens.views.branches && !config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
5091+
"group": "5_gitlens",
5092+
"order": 11
5093+
}
5094+
]
5095+
}
5096+
},
50595097
"gitlens.views.branches.setShowStashesOff": {
50605098
"label": "Hide Stashes",
50615099
"menus": {

package.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,6 +2369,13 @@
23692369
"title": "Branches View",
23702370
"order": 170,
23712371
"properties": {
2372+
"gitlens.views.branches.showRemoteBranches": {
2373+
"type": "boolean",
2374+
"default": false,
2375+
"markdownDescription": "Specifies whether to show remote branches for the default remote in the _Branches_ view",
2376+
"scope": "window",
2377+
"order": 8
2378+
},
23722379
"gitlens.views.branches.showStashes": {
23732380
"type": "boolean",
23742381
"default": false,
@@ -7612,6 +7619,14 @@
76127619
"command": "gitlens.views.branches.setShowBranchPullRequestOn",
76137620
"title": "Show Branch Pull Requests"
76147621
},
7622+
{
7623+
"command": "gitlens.views.branches.setShowRemoteBranchesOff",
7624+
"title": "Hide Remote Branches"
7625+
},
7626+
{
7627+
"command": "gitlens.views.branches.setShowRemoteBranchesOn",
7628+
"title": "Show Remote Branches"
7629+
},
76157630
{
76167631
"command": "gitlens.views.branches.setShowStashesOff",
76177632
"title": "Hide Stashes"
@@ -11239,6 +11254,14 @@
1123911254
"command": "gitlens.views.branches.setShowBranchPullRequestOn",
1124011255
"when": "false"
1124111256
},
11257+
{
11258+
"command": "gitlens.views.branches.setShowRemoteBranchesOff",
11259+
"when": "false"
11260+
},
11261+
{
11262+
"command": "gitlens.views.branches.setShowRemoteBranchesOn",
11263+
"when": "false"
11264+
},
1124211265
{
1124311266
"command": "gitlens.views.branches.setShowStashesOff",
1124411267
"when": "false"
@@ -14556,6 +14579,16 @@
1455614579
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view =~ /(branches|commits|contributors|remotes|repositories|tags|worktrees)/ && !config.gitlens.views.showRelativeDateMarkers",
1455714580
"group": "5_gitlens@10"
1455814581
},
14582+
{
14583+
"command": "gitlens.views.branches.setShowRemoteBranchesOff",
14584+
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches && config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
14585+
"group": "5_gitlens@11"
14586+
},
14587+
{
14588+
"command": "gitlens.views.branches.setShowRemoteBranchesOn",
14589+
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches && !config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
14590+
"group": "5_gitlens@11"
14591+
},
1455914592
{
1456014593
"command": "gitlens.views.branches.setShowStashesOff",
1456114594
"when": "view == gitlens.views.scm.grouped && gitlens:views:scm:grouped:view == branches && config.gitlens.views.branches.showStashes && !gitlens:hasVirtualFolders",
@@ -16799,6 +16832,16 @@
1679916832
"when": "view =~ /^gitlens\\.views\\.(branches|commits|contributors|fileHistory|lineHistory|remotes|repositories|tags|worktrees)/ && !config.gitlens.views.showRelativeDateMarkers",
1680016833
"group": "5_gitlens@10"
1680116834
},
16835+
{
16836+
"command": "gitlens.views.branches.setShowRemoteBranchesOff",
16837+
"when": "view == gitlens.views.branches && config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
16838+
"group": "5_gitlens@11"
16839+
},
16840+
{
16841+
"command": "gitlens.views.branches.setShowRemoteBranchesOn",
16842+
"when": "view == gitlens.views.branches && !config.gitlens.views.branches.showRemoteBranches && !gitlens:hasVirtualFolders",
16843+
"group": "5_gitlens@11"
16844+
},
1680216845
{
1680316846
"command": "gitlens.views.branches.setShowStashesOff",
1680416847
"when": "view == gitlens.views.branches && config.gitlens.views.branches.showStashes && !gitlens:hasVirtualFolders",

src/config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,6 +745,7 @@ export interface BranchesViewConfig {
745745
};
746746
readonly reveal: boolean;
747747
readonly showBranchComparison: false | Extract<ViewShowBranchComparison, 'branch'>;
748+
readonly showRemoteBranches: boolean;
748749
readonly showStashes: boolean;
749750
}
750751

src/constants.commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ export type TreeViewCommands = `gitlens.views.${
349349
| `setShowAvatars${'On' | 'Off'}`
350350
| `setShowBranchComparison${'On' | 'Off'}`
351351
| `setShowBranchPullRequest${'On' | 'Off'}`
352+
| `setShowRemoteBranches${'On' | 'Off'}`
352353
| `setShowStashes${'On' | 'Off'}`}`
353354
| `commits.${
354355
| 'copy'

src/git/gitProviderService.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ import type { GitBranchReference, GitReference, GitRevisionRange } from './model
7676
import { createRevisionRange, isSha, isUncommitted, isUncommittedParent } from './models/reference';
7777
import type { GitReflog } from './models/reflog';
7878
import type { GitRemote } from './models/remote';
79-
import { getRemoteThemeIconString, getVisibilityCacheKey } from './models/remote';
79+
import { getDefaultRemoteOrHighlander, getRemoteThemeIconString, getVisibilityCacheKey } from './models/remote';
8080
import type { RepositoryChangeEvent } from './models/repository';
8181
import { Repository, RepositoryChange, RepositoryChangeComparisonMode } from './models/repository';
8282
import type { GitStash } from './models/stash';
@@ -2319,6 +2319,12 @@ export class GitProviderService implements Disposable {
23192319
return undefined;
23202320
}
23212321

2322+
@log()
2323+
async getDefaultRemote(repoPath: string | Uri, _cancellation?: CancellationToken): Promise<GitRemote | undefined> {
2324+
const remotes = await this.getRemotes(repoPath, undefined, _cancellation);
2325+
return getDefaultRemoteOrHighlander(remotes);
2326+
}
2327+
23222328
@log()
23232329
async getRemote(
23242330
repoPath: string | Uri,

src/git/models/branch.ts

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export type GitBranchStatus =
3838

3939
export interface BranchSortOptions {
4040
current?: boolean;
41+
groupByType?: boolean;
4142
missingUpstream?: boolean;
4243
orderBy?: BranchSorting;
4344
openedWorktreesByBranch?: Set<string>;
@@ -311,7 +312,7 @@ export function isOfBranchRefType(branch: GitReference | undefined) {
311312
}
312313

313314
export function sortBranches(branches: GitBranch[], options?: BranchSortOptions) {
314-
options = { current: true, orderBy: configuration.get('sortBranchesBy'), ...options };
315+
options = { current: true, groupByType: true, orderBy: configuration.get('sortBranchesBy'), ...options };
315316

316317
switch (options.orderBy) {
317318
case 'date:asc':
@@ -324,7 +325,7 @@ export function sortBranches(branches: GitBranch[], options?: BranchSortOptions)
324325
(options.openedWorktreesByBranch.has(b.id) ? -1 : 1)
325326
: 0) ||
326327
(a.starred ? -1 : 1) - (b.starred ? -1 : 1) ||
327-
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
328+
(options.groupByType ? (b.remote ? -1 : 1) - (a.remote ? -1 : 1) : 0) ||
328329
(a.date == null ? -1 : a.date.getTime()) - (b.date == null ? -1 : b.date.getTime()) ||
329330
sortCompare(a.name, b.name),
330331
);
@@ -341,7 +342,7 @@ export function sortBranches(branches: GitBranch[], options?: BranchSortOptions)
341342
(a.name === 'main' ? -1 : 1) - (b.name === 'main' ? -1 : 1) ||
342343
(a.name === 'master' ? -1 : 1) - (b.name === 'master' ? -1 : 1) ||
343344
(a.name === 'develop' ? -1 : 1) - (b.name === 'develop' ? -1 : 1) ||
344-
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
345+
(options.groupByType ? (b.remote ? -1 : 1) - (a.remote ? -1 : 1) : 0) ||
345346
sortCompare(a.name, b.name),
346347
);
347348
case 'name:desc':
@@ -357,7 +358,7 @@ export function sortBranches(branches: GitBranch[], options?: BranchSortOptions)
357358
(a.name === 'main' ? -1 : 1) - (b.name === 'main' ? -1 : 1) ||
358359
(a.name === 'master' ? -1 : 1) - (b.name === 'master' ? -1 : 1) ||
359360
(a.name === 'develop' ? -1 : 1) - (b.name === 'develop' ? -1 : 1) ||
360-
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
361+
(options.groupByType ? (b.remote ? -1 : 1) - (a.remote ? -1 : 1) : 0) ||
361362
sortCompare(b.name, a.name),
362363
);
363364
case 'date:desc':
@@ -371,7 +372,7 @@ export function sortBranches(branches: GitBranch[], options?: BranchSortOptions)
371372
(options.openedWorktreesByBranch.has(b.id) ? -1 : 1)
372373
: 0) ||
373374
(a.starred ? -1 : 1) - (b.starred ? -1 : 1) ||
374-
(b.remote ? -1 : 1) - (a.remote ? -1 : 1) ||
375+
(options.groupByType ? (b.remote ? -1 : 1) - (a.remote ? -1 : 1) : 0) ||
375376
(b.date == null ? -1 : b.date.getTime()) - (a.date == null ? -1 : a.date.getTime()) ||
376377
sortCompare(b.name, a.name),
377378
);
@@ -414,3 +415,15 @@ export async function getLocalBranchByUpstream(
414415

415416
return undefined;
416417
}
418+
419+
export async function getLocalBranchUpstreamNames(branches: PageableResult<GitBranch>): Promise<Set<string>> {
420+
const remoteBranches = new Set<string>();
421+
422+
for await (const branch of branches.values()) {
423+
if (!branch.remote && branch.upstream?.name != null) {
424+
remoteBranches.add(branch.upstream.name);
425+
}
426+
}
427+
428+
return remoteBranches;
429+
}

src/git/models/remote.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ColorTheme } from 'vscode';
22
import { Uri, window } from 'vscode';
33
import { GlyphChars } from '../../constants';
4-
import { Container } from '../../container';
4+
import type { Container } from '../../container';
55
import type { HostingIntegration } from '../../plus/integrations/integration';
66
import { memoize } from '../../system/decorators/memoize';
77
import { equalsIgnoreCase, sortCompare } from '../../system/string';
@@ -25,7 +25,7 @@ export class GitRemote<TProvider extends RemoteProvider | undefined = RemoteProv
2525
) {}
2626

2727
get default() {
28-
const defaultRemote = Container.instance.storage.getWorkspace('remote:default');
28+
const defaultRemote = this.container.storage.getWorkspace('remote:default');
2929
// Check for `this.remoteKey` matches to handle previously saved data
3030
return this.name === defaultRemote || this.remoteKey === defaultRemote;
3131
}
@@ -90,15 +90,19 @@ export class GitRemote<TProvider extends RemoteProvider | undefined = RemoteProv
9090
}
9191

9292
async setAsDefault(value: boolean = true) {
93-
const repository = Container.instance.git.getRepository(this.repoPath);
93+
const repository = this.container.git.getRepository(this.repoPath);
9494
await repository?.setRemoteAsDefault(this, value);
9595
}
9696
}
9797

98+
export function getDefaultRemoteOrHighlander<T extends GitRemote>(remotes: T[]): T | undefined {
99+
return remotes.length === 1 ? remotes[0] : remotes.find(r => r.default);
100+
}
101+
98102
export function getHighlanderProviders(remotes: GitRemote<RemoteProvider>[]) {
99103
if (remotes.length === 0) return undefined;
100104

101-
const remote = remotes.length === 1 ? remotes[0] : remotes.find(r => r.default);
105+
const remote = getDefaultRemoteOrHighlander(remotes);
102106
if (remote != null) return [remote.provider];
103107

104108
const providerName = remotes[0].provider.name;
@@ -110,7 +114,7 @@ export function getHighlanderProviders(remotes: GitRemote<RemoteProvider>[]) {
110114
export function getHighlanderProviderName(remotes: GitRemote<RemoteProvider>[]) {
111115
if (remotes.length === 0) return undefined;
112116

113-
const remote = remotes.length === 1 ? remotes[0] : remotes.find(r => r.default);
117+
const remote = getDefaultRemoteOrHighlander(remotes);
114118
if (remote != null) return remote.provider.name;
115119

116120
const providerName = remotes[0].provider.name;

src/git/models/repository.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export type RepoGitProviderService = Pick<
6565
| 'getBestRemotesWithProviders'
6666
| 'getBestRemoteWithIntegration'
6767
| 'getBranch'
68+
| 'getDefaultRemote'
6869
| 'getRemote'
6970
| 'getTag'
7071
| 'getWorktree'

src/git/utils/remote-utils.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { ThemeIcon } from 'vscode';
2+
import type { IconPath } from '../../@types/vscode.iconpath';
3+
import type { Container } from '../../container';
4+
import { getIconPathUris } from '../../system/vscode/vscode';
5+
import type { GitRemote } from '../models/remote';
6+
import { getRemoteThemeIconString } from '../models/remote';
7+
8+
export function getRemoteIconPath(
9+
container: Container,
10+
remote: GitRemote | undefined,
11+
options?: { avatars?: boolean },
12+
): IconPath {
13+
if (options?.avatars && remote?.provider?.icon != null) {
14+
return getIconPathUris(container, `icon-${remote.provider.icon}.svg`);
15+
}
16+
17+
return new ThemeIcon(getRemoteThemeIconString(remote));
18+
}

src/system/paging.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import type { PagedResult } from '../git/gitProvider';
33
export class PageableResult<T> {
44
private cached: Mutable<PagedResult<T>> | undefined;
55

6-
constructor(private readonly fetch: (paging: PagedResult<T>['paging']) => Promise<PagedResult<T>>) {}
6+
constructor(
7+
private readonly fetch: (paging: PagedResult<T>['paging']) => Promise<PagedResult<T>>,
8+
seed?: PagedResult<T>,
9+
) {
10+
this.cached = seed;
11+
}
712

813
async *values(): AsyncIterable<NonNullable<T>> {
914
if (this.cached != null) {

0 commit comments

Comments
 (0)