Skip to content

Commit 5437630

Browse files
committed
Shows default remote branches in Branches view
1 parent ba5dfbb commit 5437630

File tree

7 files changed

+78
-25
lines changed

7 files changed

+78
-25
lines changed

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: 3 additions & 3 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,7 +90,7 @@ 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
}

src/git/utils/branch-utils.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ import type { Container } from '../../container';
44
import { getIconPathUris } from '../../system/vscode/vscode';
55
import type { GitBranch } from '../models/branch';
66

7-
export function getBranchIconPath(container: Container, branch: GitBranch | undefined): IconPath {
7+
export function getBranchIconPath(
8+
container: Container,
9+
branch: GitBranch | undefined,
10+
defaultIcon?: ThemeIcon,
11+
): IconPath {
812
const status = branch?.status;
913
switch (status) {
1014
case 'ahead':
@@ -14,6 +18,6 @@ export function getBranchIconPath(container: Container, branch: GitBranch | unde
1418
case 'upToDate':
1519
return getIconPathUris(container, `icon-branch-synced.svg`);
1620
default:
17-
return new ThemeIcon('git-branch');
21+
return defaultIcon ?? new ThemeIcon('git-branch');
1822
}
1923
}

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) {

src/views/branchesView.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,11 @@ export class BranchesViewNode extends RepositoriesSubscribeableNode<BranchesView
8383
if (this.children.length === 1) {
8484
const [child] = this.children;
8585

86-
const branches = await child.repo.git.getBranches({ filter: b => !b.remote });
86+
const defaultRemote = this.view.container.storage.getWorkspace('remote:default');
87+
88+
const branches = await child.repo.git.getBranches({
89+
filter: b => !b.remote || (defaultRemote != null && b.getRemoteName() === defaultRemote),
90+
});
8791
if (branches.values.length === 0) {
8892
this.view.message = 'No branches could be found.';
8993
void child.ensureSubscription();

src/views/nodes/branchNode.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ export class BranchNode
423423
const parts = await getBranchNodeParts(this.view.container, this.branch, this.current, {
424424
pendingPullRequest: this.getState('pendingPullRequest'),
425425
showAsCommits: this.options.showAsCommits,
426+
showRemoteBranchesAsCloud: this.view.type === 'branches',
426427
showStatusDecorationOnly: this.options.showStatusDecorationOnly,
427428
useBaseNameOnly: !(this.view.config.branches?.layout !== 'tree' || this.compacted || this.avoidCompacting),
428429
worktree: this.worktree,
@@ -548,6 +549,7 @@ export async function getBranchNodeParts(
548549
options?: {
549550
pendingPullRequest?: Promise<PullRequest | undefined> | undefined;
550551
showAsCommits?: boolean;
552+
showRemoteBranchesAsCloud?: boolean;
551553
showStatusDecorationOnly?: boolean;
552554
useBaseNameOnly: boolean;
553555
worktree?: GitWorktree;
@@ -747,7 +749,13 @@ export async function getBranchNodeParts(
747749
? new ThemeIcon('git-commit', iconColor)
748750
: options?.worktree != null
749751
? getWorktreeBranchIconPath(container, branch)
750-
: getBranchIconPath(container, branch),
752+
: getBranchIconPath(
753+
container,
754+
branch,
755+
branch.remote && options?.showRemoteBranchesAsCloud
756+
? new ThemeIcon('cloud')
757+
: undefined,
758+
),
751759
resourceUri: createViewDecorationUri('branch', {
752760
status: localUnpublished ? 'unpublished' : status,
753761
current: current,

src/views/nodes/branchesNode.ts

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import { ThemeIcon, TreeItem, TreeItemCollapsibleState } from 'vscode';
22
import { GitUri } from '../../git/gitUri';
3+
import type { GitBranch } from '../../git/models/branch';
4+
import { getLocalBranchUpstreamNames } from '../../git/models/branch';
35
import type { Repository } from '../../git/models/repository';
46
import { getOpenedWorktreesByBranch } from '../../git/models/worktree';
57
import { makeHierarchical } from '../../system/array';
68
import { debug } from '../../system/decorators/log';
9+
import { PageableResult } from '../../system/paging';
710
import type { ViewsWithBranchesNode } from '../viewBase';
811
import { CacheableChildrenViewNode } from './abstract/cacheableChildrenViewNode';
912
import type { ViewNode } from './abstract/viewNode';
@@ -35,27 +38,40 @@ export class BranchesNode extends CacheableChildrenViewNode<'branches', ViewsWit
3538

3639
async getChildren(): Promise<ViewNode[]> {
3740
if (this.children == null) {
38-
const branches = await this.repo.git.getBranches({
39-
// only show local branches
40-
filter: b => !b.remote,
41+
const defaultRemote = this.view.container.storage.getWorkspace('remote:default');
42+
43+
const options: Parameters<typeof this.repo.git.getBranches>['0'] = {
44+
// only show local branches or remote branches for the default remote
45+
filter: b => !b.remote || (defaultRemote != null && b.getRemoteName() === defaultRemote),
4146
sort: this.view.config.showCurrentBranchOnTop
4247
? {
4348
current: true,
49+
groupByType: defaultRemote == null,
4450
openedWorktreesByBranch: getOpenedWorktreesByBranch(this.context.worktreesByBranch),
4551
}
46-
: { current: false },
47-
});
48-
if (branches.values.length === 0) return [new MessageNode(this.view, this, 'No branches could be found.')];
52+
: { current: false, groupByType: defaultRemote == null },
53+
};
54+
55+
const branches = new PageableResult<GitBranch>(p => this.repo.git.getBranches({ ...options, paging: p }));
56+
57+
let localUpstreamNames: Set<string> | undefined;
58+
// Filter out remote branches that have a local branch
59+
if (defaultRemote != null) {
60+
localUpstreamNames = await getLocalBranchUpstreamNames(branches);
61+
}
62+
63+
const branchNodes: BranchNode[] = [];
4964

50-
// TODO@eamodio handle paging
51-
const branchNodes = branches.values.map(
52-
b =>
65+
for await (const branch of branches.values()) {
66+
if (branch.remote && localUpstreamNames?.has(branch.name)) continue;
67+
68+
branchNodes.push(
5369
new BranchNode(
54-
GitUri.fromRepoPath(this.uri.repoPath!, b.ref),
70+
GitUri.fromRepoPath(this.uri.repoPath!, branch.ref),
5571
this.view,
5672
this,
5773
this.repo,
58-
b,
74+
branch,
5975
false,
6076
{
6177
showComparison:
@@ -64,7 +80,10 @@ export class BranchesNode extends CacheableChildrenViewNode<'branches', ViewsWit
6480
: this.view.config.showBranchComparison,
6581
},
6682
),
67-
);
83+
);
84+
}
85+
86+
if (branchNodes.length === 0) return [new MessageNode(this.view, this, 'No branches could be found.')];
6887
if (this.view.config.branches.layout === 'list') return branchNodes;
6988

7089
const hierarchy = makeHierarchical(

0 commit comments

Comments
 (0)