@@ -8,10 +8,18 @@ import { Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider
8
8
import { Repository , Resource } from './repository' ;
9
9
import { IDisposable , filterEvent } from './util' ;
10
10
import { toGitUri } from './uri' ;
11
- import { Branch , RefType , Status } from './api/git' ;
11
+ import { Branch , RefType , UpstreamRef } from './api/git' ;
12
12
import { emojify , ensureEmojis } from './emoji' ;
13
13
import { Operation } from './operation' ;
14
14
15
+ function isBranchRefEqual ( brach1 : Branch | undefined , branch2 : Branch | undefined ) : boolean {
16
+ return brach1 ?. name === branch2 ?. name && brach1 ?. commit === branch2 ?. commit ;
17
+ }
18
+
19
+ function isUpstreamRefEqual ( upstream1 : UpstreamRef | undefined , upstream2 : UpstreamRef | undefined ) : boolean {
20
+ return upstream1 ?. name === upstream2 ?. name && upstream1 ?. remote === upstream2 ?. remote && upstream1 ?. commit === upstream2 ?. commit ;
21
+ }
22
+
15
23
export class GitHistoryProvider implements SourceControlHistoryProvider , FileDecorationProvider , IDisposable {
16
24
17
25
private readonly _onDidChangeCurrentHistoryItemGroup = new EventEmitter < void > ( ) ;
@@ -21,10 +29,15 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
21
29
readonly onDidChangeFileDecorations : Event < Uri [ ] > = this . _onDidChangeDecorations . event ;
22
30
23
31
private _HEAD : Branch | undefined ;
32
+ private _HEADBase : UpstreamRef | undefined ;
24
33
private _currentHistoryItemGroup : SourceControlHistoryItemGroup | undefined ;
25
34
26
35
get currentHistoryItemGroup ( ) : SourceControlHistoryItemGroup | undefined { return this . _currentHistoryItemGroup ; }
27
36
set currentHistoryItemGroup ( value : SourceControlHistoryItemGroup | undefined ) {
37
+ if ( this . _currentHistoryItemGroup === undefined && value === undefined ) {
38
+ return ;
39
+ }
40
+
28
41
this . _currentHistoryItemGroup = value ;
29
42
this . _onDidChangeCurrentHistoryItemGroup . fire ( ) ;
30
43
}
@@ -41,30 +54,31 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
41
54
}
42
55
43
56
private async onDidRunGitStatus ( ) : Promise < void > {
44
- // Check if HEAD has changed
45
- if ( this . _HEAD ?. name === this . repository . HEAD ?. name &&
46
- this . _HEAD ?. commit === this . repository . HEAD ?. commit &&
47
- this . _HEAD ?. upstream ?. name === this . repository . HEAD ?. upstream ?. name &&
48
- this . _HEAD ?. upstream ?. remote === this . repository . HEAD ?. upstream ?. remote &&
49
- this . _HEAD ?. upstream ?. commit === this . repository . HEAD ?. upstream ?. commit ) {
57
+ // Check if HEAD does not support incoming/outgoing (detached commit, tag)
58
+ if ( ! this . repository . HEAD ?. name || ! this . repository . HEAD ?. commit || this . repository . HEAD . type === RefType . Tag ) {
59
+ this . _HEAD = this . _HEADBase = undefined ;
60
+ this . currentHistoryItemGroup = undefined ;
50
61
return ;
51
62
}
52
63
53
- this . _HEAD = this . repository . HEAD ;
64
+ // Resolve HEAD base
65
+ const HEADBase = await this . resolveHEADBase ( this . repository . HEAD ) ;
54
66
55
- // Check if HEAD supports incoming/outgoing (not a tag, not detached)
56
- if ( ! this . _HEAD ?. name || ! this . _HEAD ?. commit || this . _HEAD . type === RefType . Tag ) {
57
- this . currentHistoryItemGroup = undefined ;
67
+ // Check if HEAD or HEADBase has changed
68
+ if ( isBranchRefEqual ( this . _HEAD , this . repository . HEAD ) && isUpstreamRefEqual ( this . _HEADBase , HEADBase ) ) {
58
69
return ;
59
70
}
60
71
72
+ this . _HEAD = this . repository . HEAD ;
73
+ this . _HEADBase = HEADBase ;
74
+
61
75
this . currentHistoryItemGroup = {
62
- id : `refs/heads/${ this . _HEAD . name } ` ,
63
- label : this . _HEAD . name ,
64
- upstream : this . _HEAD . upstream ?
76
+ id : `refs/heads/${ this . _HEAD . name ?? '' } ` ,
77
+ label : this . _HEAD . name ?? '' ,
78
+ base : this . _HEADBase ?
65
79
{
66
- id : `refs/remotes/${ this . _HEAD . upstream . remote } /${ this . _HEAD . upstream . name } ` ,
67
- label : `${ this . _HEAD . upstream . remote } /${ this . _HEAD . upstream . name } ` ,
80
+ id : `refs/remotes/${ this . _HEADBase . remote } /${ this . _HEADBase . name } ` ,
81
+ label : `${ this . _HEADBase . remote } /${ this . _HEADBase . name } ` ,
68
82
} : undefined
69
83
} ;
70
84
}
@@ -138,7 +152,10 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
138
152
} ) ;
139
153
140
154
// History item change decoration
141
- const fileDecoration = this . getHistoryItemChangeFileDecoration ( change . status ) ;
155
+ const letter = Resource . getStatusLetter ( change . status ) ;
156
+ const tooltip = Resource . getStatusText ( change . status ) ;
157
+ const color = Resource . getStatusColor ( change . status ) ;
158
+ const fileDecoration = new FileDecoration ( letter , tooltip , color ) ;
142
159
this . historyItemDecorations . set ( historyItemUri . toString ( ) , fileDecoration ) ;
143
160
144
161
historyItemChangesUri . push ( historyItemUri ) ;
@@ -148,40 +165,6 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
148
165
return historyItemChanges ;
149
166
}
150
167
151
- async resolveHistoryItemGroupBase ( historyItemGroupId : string ) : Promise < SourceControlHistoryItemGroup | undefined > {
152
- // TODO - support for all history item groups
153
- if ( historyItemGroupId !== this . currentHistoryItemGroup ?. id ) {
154
- return undefined ;
155
- }
156
-
157
- if ( this . currentHistoryItemGroup ?. upstream ) {
158
- return this . currentHistoryItemGroup . upstream ;
159
- }
160
-
161
- // Branch base
162
- try {
163
- const branchBase = await this . repository . getBranchBase ( historyItemGroupId ) ;
164
-
165
- if ( branchBase ?. name && branchBase ?. type === RefType . Head ) {
166
- return {
167
- id : `refs/heads/${ branchBase . name } ` ,
168
- label : branchBase . name
169
- } ;
170
- }
171
- if ( branchBase ?. name && branchBase . remote && branchBase ?. type === RefType . RemoteHead ) {
172
- return {
173
- id : `refs/remotes/${ branchBase . remote } /${ branchBase . name } ` ,
174
- label : `${ branchBase . remote } /${ branchBase . name } `
175
- } ;
176
- }
177
- }
178
- catch ( err ) {
179
- this . logger . error ( `Failed to get branch base for '${ historyItemGroupId } ': ${ err . message } ` ) ;
180
- }
181
-
182
- return undefined ;
183
- }
184
-
185
168
async resolveHistoryItemGroupCommonAncestor ( refId1 : string , refId2 : string ) : Promise < { id : string ; ahead : number ; behind : number } | undefined > {
186
169
const ancestor = await this . repository . getMergeBase ( refId1 , refId2 ) ;
187
170
if ( ! ancestor ) {
@@ -202,12 +185,29 @@ export class GitHistoryProvider implements SourceControlHistoryProvider, FileDec
202
185
return this . historyItemDecorations . get ( uri . toString ( ) ) ;
203
186
}
204
187
205
- private getHistoryItemChangeFileDecoration ( status : Status ) : FileDecoration {
206
- const letter = Resource . getStatusLetter ( status ) ;
207
- const tooltip = Resource . getStatusText ( status ) ;
208
- const color = Resource . getStatusColor ( status ) ;
188
+ private async resolveHEADBase ( HEAD : Branch ) : Promise < UpstreamRef | undefined > {
189
+ // Upstream
190
+ if ( HEAD . upstream ) {
191
+ return HEAD . upstream ;
192
+ }
209
193
210
- return new FileDecoration ( letter , tooltip , color ) ;
194
+ try {
195
+ const remoteBranch = await this . repository . getBranchBase ( HEAD . name ?? '' ) ;
196
+ if ( ! remoteBranch ?. remote || ! remoteBranch ?. name || ! remoteBranch ?. commit || remoteBranch ?. type !== RefType . RemoteHead ) {
197
+ return undefined ;
198
+ }
199
+
200
+ return {
201
+ name : remoteBranch . name ,
202
+ remote : remoteBranch . remote ,
203
+ commit : remoteBranch . commit
204
+ } ;
205
+ }
206
+ catch ( err ) {
207
+ this . logger . error ( `Failed to get branch base for '${ HEAD . name } ': ${ err . message } ` ) ;
208
+ }
209
+
210
+ return undefined ;
211
211
}
212
212
213
213
dispose ( ) : void {
0 commit comments