@@ -7,7 +7,7 @@ import type { GitFileStatus } from '../../../../git/models/fileStatus';
77import { deletedOrMissing } from '../../../../git/models/revision' ;
88import type { GitTreeEntry } from '../../../../git/models/tree' ;
99import { getShaAndFileSummaryLogParser } from '../../../../git/parsers/logParser' ;
10- import { parseGitLsFiles , parseGitTree } from '../../../../git/parsers/treeParser' ;
10+ import { parseGitLsFilesStaged , parseGitTree } from '../../../../git/parsers/treeParser' ;
1111import {
1212 isRevisionWithSuffix ,
1313 isSha ,
@@ -22,6 +22,8 @@ import { first } from '../../../../system/iterable';
2222import type { Git } from '../git' ;
2323import type { LocalGitProvider } from '../localGitProvider' ;
2424
25+ const emptyArray : readonly any [ ] = Object . freeze ( [ ] ) ;
26+
2527export class RevisionGitSubProvider implements GitRevisionSubProvider {
2628 constructor (
2729 private readonly container : Container ,
@@ -30,6 +32,32 @@ export class RevisionGitSubProvider implements GitRevisionSubProvider {
3032 private readonly provider : LocalGitProvider ,
3133 ) { }
3234
35+ exists ( repoPath : string , path : string , rev ?: string ) : Promise < boolean > ;
36+ exists ( repoPath : string , path : string , options ?: { untracked ?: boolean } ) : Promise < boolean > ;
37+ async exists ( repoPath : string , path : string , revOrOptions ?: string | { untracked ?: boolean } ) : Promise < boolean > {
38+ let rev ;
39+ let untracked ;
40+ if ( typeof revOrOptions === 'string' ) {
41+ rev = revOrOptions ;
42+ } else if ( revOrOptions != null ) {
43+ untracked = revOrOptions . untracked ;
44+ }
45+
46+ const args = [ 'ls-files' ] ;
47+ if ( rev ) {
48+ if ( ! isUncommitted ( rev ) ) {
49+ args . push ( `--with-tree=${ rev } ` ) ;
50+ } else if ( isUncommittedStaged ( rev ) ) {
51+ args . push ( '--stage' ) ;
52+ }
53+ } else if ( untracked ) {
54+ args . push ( '-o' ) ;
55+ }
56+
57+ const result = await this . git . exec ( { cwd : repoPath , errors : GitErrorHandling . Ignore } , ...args , '--' , path ) ;
58+ return Boolean ( result . stdout . trim ( ) ) ;
59+ }
60+
3361 @gate ( )
3462 @log ( )
3563 getRevisionContent ( repoPath : string , rev : string , path : string ) : Promise < Uint8Array | undefined > {
@@ -43,47 +71,46 @@ export class RevisionGitSubProvider implements GitRevisionSubProvider {
4371 @gate ( )
4472 @log ( )
4573 async getTreeEntryForRevision ( repoPath : string , rev : string , path : string ) : Promise < GitTreeEntry | undefined > {
46- if ( repoPath == null || ! path ) return undefined ;
74+ if ( ! repoPath || ! path ) return undefined ;
4775
4876 const [ relativePath , root ] = splitPath ( path , repoPath ) ;
4977
5078 if ( isUncommittedStaged ( rev ) ) {
51- let data = await this . git . ls_files ( root , relativePath , { rev : rev } ) ;
52- const [ entry ] = parseGitLsFiles ( data ) ;
79+ let result = await this . git . exec (
80+ { cwd : root , errors : GitErrorHandling . Ignore } ,
81+ 'ls-files' ,
82+ '--stage' ,
83+ '--' ,
84+ relativePath ,
85+ ) ;
86+
87+ const [ entry ] = parseGitLsFilesStaged ( result . stdout , true ) ;
5388 if ( entry == null ) return undefined ;
5489
55- const result = await this . git . exec ( { cwd : repoPath } , 'cat-file' , '-s' , entry . oid ) ;
56- data = result . stdout . trim ( ) ;
57- const size = data ? parseInt ( data , 10 ) : 0 ;
90+ result = await this . git . exec ( { cwd : root } , 'cat-file' , '-s' , entry . oid ) ;
91+ const size = result ? parseInt ( result . stdout . trim ( ) , 10 ) : 0 ;
5892
59- return {
60- ref : rev ,
61- oid : entry . oid ,
62- path : relativePath ,
63- size : size ,
64- type : 'blob' ,
65- } ;
93+ return { ref : rev , oid : entry . oid , path : relativePath , size : size , type : 'blob' } ;
6694 }
6795
68- const entries = await this . getTreeForRevisionCore ( repoPath , rev , path ) ;
69- return entries [ 0 ] ;
96+ const [ entry ] = await this . getTreeForRevisionCore ( repoPath , rev , path ) ;
97+ return entry ;
7098 }
7199
72100 @log ( )
73101 async getTreeForRevision ( repoPath : string , rev : string ) : Promise < GitTreeEntry [ ] > {
74- if ( repoPath == null ) return [ ] ;
75-
76- return this . getTreeForRevisionCore ( repoPath , rev ) ;
102+ return repoPath ? this . getTreeForRevisionCore ( repoPath , rev ) : [ ] ;
77103 }
78104
79105 @gate ( )
80106 private async getTreeForRevisionCore ( repoPath : string , rev : string , path ?: string ) : Promise < GitTreeEntry [ ] > {
81- const args = path ? [ '-l' , rev , '--' , path ] : [ '-lrt' , rev , '--' ] ;
82- const result = await this . git . exec ( { cwd : repoPath , errors : GitErrorHandling . Ignore } , 'ls-tree' , ...args ) ;
107+ const hasPath = Boolean ( path ) ;
108+ const args = hasPath ? [ 'ls-tree' , '-l' , rev , '--' , path ] : [ 'ls-tree' , '-lrt' , rev , '--' ] ;
109+ const result = await this . git . exec ( { cwd : repoPath , errors : GitErrorHandling . Ignore } , ...args ) ;
83110 const data = result . stdout . trim ( ) ;
84- if ( ! data ) return [ ] ;
111+ if ( ! data ) return emptyArray as GitTreeEntry [ ] ;
85112
86- return parseGitTree ( data , rev ) ;
113+ return parseGitTree ( data , rev , hasPath ) ;
87114 }
88115
89116 @log ( )
0 commit comments