-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
branch.ts
127 lines (106 loc) · 3.68 KB
/
branch.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
'use strict';
import { StarredBranches, WorkspaceState } from '../../constants';
import { Container } from '../../container';
import { Git } from '../git';
import { GitStatus } from './status';
export interface GitTrackingState {
ahead: number;
behind: number;
}
export class GitBranch {
readonly detached: boolean;
readonly id: string;
readonly tracking?: string;
readonly state: GitTrackingState;
constructor(
public readonly repoPath: string,
public readonly name: string,
public readonly remote: boolean,
public readonly current: boolean,
public readonly sha?: string,
tracking?: string,
ahead: number = 0,
behind: number = 0,
detached: boolean = false
) {
this.id = `${repoPath}|${remote ? 'remotes/' : 'heads/'}${name}`;
this.detached = detached || (this.current ? GitBranch.isDetached(name) : false);
if (this.detached) {
this.name = GitBranch.formatDetached(this.sha!);
}
this.tracking = tracking == null || tracking.length === 0 ? undefined : tracking;
this.state = {
ahead: ahead,
behind: behind
};
}
get ref() {
return this.detached ? this.sha! : this.name;
}
private _basename: string | undefined;
getBasename(): string {
if (this._basename === undefined) {
const name = this.getName();
const index = name.lastIndexOf('/');
this._basename = index !== -1 ? name.substring(index + 1) : name;
}
return this._basename;
}
private _name: string | undefined;
getName(): string {
if (this._name === undefined) {
this._name = this.remote ? this.name.substring(this.name.indexOf('/') + 1) : this.name;
}
return this._name;
}
getRemote(): string | undefined {
if (this.remote) return GitBranch.getRemote(this.name);
if (this.tracking !== undefined) return GitBranch.getRemote(this.tracking);
return undefined;
}
getTrackingStatus(options?: {
empty?: string;
expand?: boolean;
prefix?: string;
separator?: string;
suffix?: string;
}): string {
return GitStatus.getUpstreamStatus(this.tracking, this.state, options);
}
get starred() {
const starred = Container.context.workspaceState.get<StarredBranches>(WorkspaceState.StarredBranches);
return starred !== undefined && starred[this.id] === true;
}
star() {
return this.updateStarred(true);
}
unstar() {
return this.updateStarred(false);
}
private async updateStarred(star: boolean) {
let starred = Container.context.workspaceState.get<StarredBranches>(WorkspaceState.StarredBranches);
if (starred === undefined) {
starred = Object.create(null);
}
if (star) {
starred![this.id] = true;
}
else {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { [this.id]: _, ...rest } = starred!;
starred = rest;
}
await Container.context.workspaceState.update(WorkspaceState.StarredBranches, starred);
}
static getRemote(branch: string): string {
return branch.substring(0, branch.indexOf('/'));
}
static formatDetached(sha: string): string {
return `(${Git.shortenSha(sha)}...)`;
}
static isDetached(name: string): boolean {
// If there is whitespace in the name assume this is not a valid branch name
// Deals with detached HEAD states
return name.match(/\s/) !== null || name.match(/\(detached\)/) !== null;
}
}