@@ -12,7 +12,7 @@ import type {
12
12
import { GitBranch } from '../../../../git/models/branch' ;
13
13
import type { MergeConflict } from '../../../../git/models/mergeConflict' ;
14
14
import type { GitBranchReference } from '../../../../git/models/reference' ;
15
- import { parseGitBranches } from '../../../../git/parsers/branchParser' ;
15
+ import { parseGitBranches , parseGitBranchesDefaultFormat } from '../../../../git/parsers/branchParser' ;
16
16
import { parseMergeTreeConflict } from '../../../../git/parsers/mergeTreeParser' ;
17
17
import { getReferenceFromBranch } from '../../../../git/utils/-webview/reference.utils' ;
18
18
import type { BranchSortOptions } from '../../../../git/utils/-webview/sorting' ;
@@ -28,7 +28,9 @@ import { getLogScope } from '../../../../system/logger.scope';
28
28
import { PageableResult } from '../../../../system/paging' ;
29
29
import { getSettledValue } from '../../../../system/promise' ;
30
30
import type { Git } from '../git' ;
31
+ import { GitErrors , gitLogDefaultConfigs } from '../git' ;
31
32
import type { LocalGitProvider } from '../localGitProvider' ;
33
+ import { RunError } from '../shell' ;
32
34
33
35
const emptyPagedResult : PagedResult < any > = Object . freeze ( { values : [ ] } ) ;
34
36
@@ -76,7 +78,16 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
76
78
77
79
const [ pausedOpStatusResult , committerDateResult ] = await Promise . allSettled ( [
78
80
isDetachedHead ( name ) ? this . provider . status ?. getPausedOperationStatus ( repoPath ) : undefined ,
79
- this . git . log__recent_committerdate ( repoPath , commitOrdering ) ,
81
+ this . git
82
+ . exec (
83
+ { cwd : repoPath , configs : gitLogDefaultConfigs , errors : GitErrorHandling . Ignore } ,
84
+ 'log' ,
85
+ '-n1' ,
86
+ '--format=%ct' ,
87
+ commitOrdering ? `--${ commitOrdering } -order` : undefined ,
88
+ '--' ,
89
+ )
90
+ . then ( data => ( ! data . length ? undefined : data . trim ( ) ) ) ,
80
91
] ) ;
81
92
82
93
const committerDate = getSettledValue ( committerDateResult ) ;
@@ -114,7 +125,13 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
114
125
if ( resultsPromise == null ) {
115
126
async function load ( this : BranchesGitSubProvider ) : Promise < PagedResult < GitBranch > > {
116
127
try {
117
- const data = await this . git . for_each_ref__branch ( repoPath , { all : true } ) ;
128
+ const data = await this . git . exec (
129
+ { cwd : repoPath } ,
130
+ 'for-each-ref' ,
131
+ `--format=${ parseGitBranchesDefaultFormat } ` ,
132
+ 'refs/heads' ,
133
+ 'refs/remotes' ,
134
+ ) ;
118
135
// If we don't get any data, assume the repo doesn't have any commits yet so check if we have a current branch
119
136
if ( ! data ?. length ) {
120
137
const current = await this . getCurrentBranch ( repoPath ) ;
@@ -275,7 +292,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
275
292
276
293
if ( remote ) {
277
294
try {
278
- const data = await this . git . ls_remote__HEAD ( repoPath , remote ) ;
295
+ const data = await this . git . exec ( { cwd : repoPath } , 'ls- remote' , '--symref' , remote , 'HEAD' ) ;
279
296
if ( data == null ) return undefined ;
280
297
281
298
const match = / r e f : \s ( \S + ) \s + H E A D / m. exec ( data ) ;
@@ -287,7 +304,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
287
304
}
288
305
289
306
try {
290
- const data = await this . git . symbolic_ref ( repoPath , ` refs/remotes/origin/HEAD` ) ;
307
+ const data = await this . git . exec ( { cwd : repoPath } , 'symbolic-ref' , '--short' , ' refs/remotes/origin/HEAD' ) ;
291
308
return data ?. trim ( ) || undefined ;
292
309
} catch { }
293
310
@@ -304,8 +321,14 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
304
321
const scope = getLogScope ( ) ;
305
322
306
323
try {
307
- const data = await this . git . merge_base ( repoPath , ref1 , ref2 , options ) ;
308
- if ( data == null ) return undefined ;
324
+ const data = await this . git . exec (
325
+ { cwd : repoPath } ,
326
+ 'merge-base' ,
327
+ options ?. forkPoint ? '--fork-point' : undefined ,
328
+ ref1 ,
329
+ ref2 ,
330
+ ) ;
331
+ if ( ! data ) return undefined ;
309
332
310
333
return data . split ( '\n' ) [ 0 ] . trim ( ) || undefined ;
311
334
} catch ( ex ) {
@@ -316,7 +339,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
316
339
317
340
@log ( )
318
341
async createBranch ( repoPath : string , name : string , sha : string ) : Promise < void > {
319
- await this . git . branch ( repoPath , name , sha ) ;
342
+ await this . git . exec ( { cwd : repoPath } , 'branch' , name , sha ) ;
320
343
}
321
344
322
345
@log ( )
@@ -371,14 +394,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
371
394
} catch { }
372
395
373
396
// Cherry-pick detection (handles cherry-picks, rebases, etc)
374
- const data = await this . git . exec < string > (
375
- { cwd : repoPath } ,
376
- 'cherry' ,
377
- '--abbrev' ,
378
- '-v' ,
379
- into . name ,
380
- branch . name ,
381
- ) ;
397
+ const data = await this . git . exec ( { cwd : repoPath } , 'cherry' , '--abbrev' , '-v' , into . name , branch . name ) ;
382
398
// Check if there are no lines or all lines startwith a `-` (i.e. likely merged)
383
399
if ( ! data || data . split ( '\n' ) . every ( l => l . startsWith ( '-' ) ) ) {
384
400
return { merged : true , confidence : 'high' } ;
@@ -415,9 +431,37 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
415
431
416
432
let data ;
417
433
try {
418
- data = await this . git . merge_tree ( repoPath , branch , targetBranch , '-z' , '--name-only' , '--no-messages' ) ;
434
+ data = await this . git . exec (
435
+ { cwd : repoPath , errors : GitErrorHandling . Throw } ,
436
+ 'merge-tree' ,
437
+ '-z' ,
438
+ '--name-only' ,
439
+ '--no-messages' ,
440
+ branch ,
441
+ targetBranch ,
442
+ ) ;
419
443
} catch ( ex ) {
420
- Logger . error ( ex , scope ) ;
444
+ const msg : string = ex ?. toString ( ) ?? '' ;
445
+ if ( GitErrors . notAValidObjectName . test ( msg ) ) {
446
+ Logger . error (
447
+ ex ,
448
+ scope ,
449
+ `'${ targetBranch } ' or '${ branch } ' not found - ensure the branches exist and are fully qualified (e.g. 'refs/heads/main')` ,
450
+ ) ;
451
+ } else if ( GitErrors . badRevision . test ( msg ) ) {
452
+ Logger . error ( ex , scope , `Invalid branch name: ${ msg . slice ( msg . indexOf ( "'" ) ) } ` ) ;
453
+ } else if ( GitErrors . noMergeBase . test ( msg ) ) {
454
+ Logger . error (
455
+ ex ,
456
+ scope ,
457
+ `Unable to merge '${ branch } ' and '${ targetBranch } ' as they have no common ancestor` ,
458
+ ) ;
459
+ } else if ( ex instanceof RunError ) {
460
+ data = ex . stdout ;
461
+ } else {
462
+ Logger . error ( ex , scope ) ;
463
+ debugger ;
464
+ }
421
465
}
422
466
if ( ! data ) return undefined ;
423
467
@@ -496,7 +540,7 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
496
540
options ?: { upstream : true } ,
497
541
) : Promise < string | undefined > {
498
542
try {
499
- let data = await this . git . reflog ( repoPath , undefined , ref , '--grep-reflog=branch: Created from *.' ) ;
543
+ let data = await this . git . exec ( { cwd : repoPath } , 'reflog' , ref , '--grep-reflog=branch: Created from *.' ) ;
500
544
501
545
let entries = data . split ( '\n' ) . filter ( entry => Boolean ( entry ) ) ;
502
546
if ( entries . length !== 1 ) return undefined ;
@@ -517,12 +561,13 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
517
561
}
518
562
519
563
// Check if branch was created from HEAD
520
- data = await this . git . reflog (
521
- repoPath ,
522
- undefined ,
564
+ data = await this . git . exec (
565
+ { cwd : repoPath } ,
566
+ 'reflog' ,
523
567
'HEAD' ,
524
568
`--grep-reflog=checkout: moving from .* to ${ ref . replace ( 'refs/heads/' , '' ) } ` ,
525
569
) ;
570
+
526
571
entries = data . split ( '\n' ) . filter ( entry => Boolean ( entry ) ) ;
527
572
if ( ! entries . length ) return undefined ;
528
573
@@ -562,11 +607,11 @@ export class BranchesGitSubProvider implements GitBranchesSubProvider {
562
607
563
608
@log ( )
564
609
async renameBranch ( repoPath : string , oldName : string , newName : string ) : Promise < void > {
565
- await this . git . branch ( repoPath , '-m' , oldName , newName ) ;
610
+ await this . git . exec ( { cwd : repoPath } , 'branch' , '-m' , oldName , newName ) ;
566
611
}
567
612
568
613
private async getValidatedBranchName ( repoPath : string , name : string ) : Promise < string | undefined > {
569
- const data = await this . git . exec < string > (
614
+ const data = await this . git . exec (
570
615
{ cwd : repoPath , errors : GitErrorHandling . Ignore } ,
571
616
'rev-parse' ,
572
617
'--verify' ,
0 commit comments