@@ -12,12 +12,17 @@ import type {
1212import { GitBranch } from '../../../../git/models/branch' ;
1313import type { MergeConflict } from '../../../../git/models/mergeConflict' ;
1414import type { GitBranchReference } from '../../../../git/models/reference' ;
15- import { parseGitBranches , parseGitBranchesDefaultFormat } from '../../../../git/parsers/branchParser' ;
1615import { parseMergeTreeConflict } from '../../../../git/parsers/mergeTreeParser' ;
16+ import { getBranchParser } from '../../../../git/parsers/refParser' ;
1717import { getReferenceFromBranch } from '../../../../git/utils/-webview/reference.utils' ;
1818import type { BranchSortOptions } from '../../../../git/utils/-webview/sorting' ;
1919import { sortBranches , sortContributors } from '../../../../git/utils/-webview/sorting' ;
20- import { getLocalBranchByUpstream , isDetachedHead } from '../../../../git/utils/branch.utils' ;
20+ import {
21+ getLocalBranchByUpstream ,
22+ isDetachedHead ,
23+ isRemoteHEAD ,
24+ parseUpstream ,
25+ } from '../../../../git/utils/branch.utils' ;
2126import { createRevisionRange } from '../../../../git/utils/revision.utils' ;
2227import { configuration } from '../../../../system/-webview/configuration' ;
2328import { filterMap } from '../../../../system/array' ;
@@ -26,7 +31,9 @@ import { log } from '../../../../system/decorators/log';
2631import { Logger } from '../../../../system/logger' ;
2732import { getLogScope } from '../../../../system/logger.scope' ;
2833import { PageableResult } from '../../../../system/paging' ;
34+ import { normalizePath } from '../../../../system/path' ;
2935import { getSettledValue } from '../../../../system/promise' ;
36+ import { maybeStopWatch } from '../../../../system/stopwatch' ;
3037import type { Git } from '../git' ;
3138import { GitErrors , gitLogDefaultConfigs } from '../git' ;
3239import type { LocalGitProvider } from '../localGitProvider' ;
@@ -76,7 +83,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
7683
7784 const [ name , upstream ] = data [ 0 ] . split ( '\n' ) ;
7885
79- const [ pausedOpStatusResult , committerDateResult ] = await Promise . allSettled ( [
86+ const [ pausedOpStatusResult , committerDateResult , defaultWorktreePathResult ] = await Promise . allSettled ( [
8087 isDetachedHead ( name ) ? this . provider . status ?. getPausedOperationStatus ( repoPath ) : undefined ,
8188 this . git
8289 . exec (
@@ -88,21 +95,23 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
8895 '--' ,
8996 )
9097 . then ( data => ( ! data . length ? undefined : data . trim ( ) ) ) ,
98+ this . provider . config . getDefaultWorktreePath ?.( repoPath ) ,
9199 ] ) ;
92100
93101 const committerDate = getSettledValue ( committerDateResult ) ;
94102 const pausedOpStatus = getSettledValue ( pausedOpStatusResult ) ;
95103 const rebaseStatus = pausedOpStatus ?. type === 'rebase' ? pausedOpStatus : undefined ;
104+ const defaultWorktreePath = getSettledValue ( defaultWorktreePathResult ) ;
96105
97106 return new GitBranch (
98107 this . container ,
99108 repoPath ,
100- rebaseStatus ?. incoming . name ?? name ,
101- false ,
109+ rebaseStatus ?. incoming . name ?? `refs/heads/${ name } ` ,
102110 true ,
103111 committerDate != null ? new Date ( Number ( committerDate ) * 1000 ) : undefined ,
104112 data [ 1 ] ,
105113 upstream ? { name : upstream , missing : false , state : { ahead : 0 , behind : 0 } } : undefined ,
114+ { path : repoPath , isDefault : repoPath === defaultWorktreePath } ,
106115 undefined ,
107116 rebaseStatus != null ,
108117 ) ;
@@ -119,14 +128,18 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
119128 ) : Promise < PagedResult < GitBranch > > {
120129 if ( repoPath == null ) return emptyPagedResult ;
121130
131+ const scope = getLogScope ( ) ;
132+
122133 let resultsPromise = this . cache . branches ?. get ( repoPath ) ;
123134 if ( resultsPromise == null ) {
124135 async function load ( this : BranchesGitSubProvider ) : Promise < PagedResult < GitBranch > > {
125136 try {
137+ const parser = getBranchParser ( ) ;
138+
126139 const data = await this . git . exec (
127140 { cwd : repoPath } ,
128141 'for-each-ref' ,
129- `--format= ${ parseGitBranchesDefaultFormat } ` ,
142+ ... parser . arguments ,
130143 'refs/heads' ,
131144 'refs/remotes' ,
132145 ) ;
@@ -136,11 +149,52 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
136149 return current != null ? { values : [ current ] } : emptyPagedResult ;
137150 }
138151
139- const branches = parseGitBranches ( this . container , data , repoPath ) ;
152+ const defaultWorktreePath = await this . provider . config . getDefaultWorktreePath ?.( repoPath ) ;
153+
154+ using sw = maybeStopWatch ( scope , { log : false , logLevel : 'debug' } ) ;
155+
156+ const branches : GitBranch [ ] = [ ] ;
157+
158+ let hasCurrent = false ;
159+
160+ for ( const entry of parser . parse ( data ) ) {
161+ // Skip HEAD refs in remote branches
162+ if ( isRemoteHEAD ( entry . name ) ) continue ;
163+
164+ const upstream = parseUpstream ( entry . upstream , entry . upstreamTracking ) ;
165+
166+ const current = entry . current === '*' ;
167+ if ( current ) {
168+ hasCurrent = true ;
169+ }
170+
171+ const worktreePath = normalizePath ( entry . worktreePath ) ;
172+
173+ branches . push (
174+ new GitBranch (
175+ this . container ,
176+ repoPath ,
177+ entry . name ,
178+ current ,
179+ entry . date ? new Date ( entry . date ) : undefined ,
180+ entry . sha ,
181+ upstream ,
182+ worktreePath
183+ ? {
184+ path : worktreePath ,
185+ isDefault : worktreePath === defaultWorktreePath ,
186+ }
187+ : undefined ,
188+ ) ,
189+ ) ;
190+ }
191+
192+ sw ?. stop ( { suffix : ` parsed ${ branches . length } branches` } ) ;
193+
140194 if ( ! branches . length ) return emptyPagedResult ;
141195
142196 // If we don't have a current branch, check if we can find it another way (likely detached head)
143- if ( ! branches . some ( b => b . current ) ) {
197+ if ( ! hasCurrent ) {
144198 const current = await this . getCurrentBranch ( repoPath ) ;
145199 if ( current != null ) {
146200 // replace the current branch if it already exists and add it first if not
0 commit comments