@@ -12,7 +12,7 @@ import * as which from 'which';
12
12
import { EventEmitter } from 'events' ;
13
13
import * as iconv from '@vscode/iconv-lite-umd' ;
14
14
import * as filetype from 'file-type' ;
15
- import { assign , groupBy , IDisposable , toDisposable , dispose , mkdirp , readBytes , detectUnicodeEncoding , Encoding , onceEvent , splitInChunks , Limiter , Versions , isWindows , pathEquals , isMacintosh } from './util' ;
15
+ import { assign , groupBy , IDisposable , toDisposable , dispose , mkdirp , readBytes , detectUnicodeEncoding , Encoding , onceEvent , splitInChunks , Limiter , Versions , isWindows , pathEquals , isMacintosh , isDescendant } from './util' ;
16
16
import { CancellationError , CancellationToken , ConfigurationChangeEvent , LogOutputChannel , Progress , Uri , workspace } from 'vscode' ;
17
17
import { detectEncoding } from './encoding' ;
18
18
import { Ref , RefType , Branch , Remote , ForcePushMode , GitErrorCodes , LogOptions , Change , Status , CommitOptions , RefQuery , InitOptions } from './api/git' ;
@@ -477,18 +477,18 @@ export class Git {
477
477
return folderPath ;
478
478
}
479
479
480
- async getRepositoryRoot ( repositoryPath : string ) : Promise < string > {
481
- const result = await this . exec ( repositoryPath , [ 'rev-parse' , '--show-toplevel' ] ) ;
480
+ async getRepositoryRoot ( pathInsidePossibleRepository : string ) : Promise < string > {
481
+ const result = await this . exec ( pathInsidePossibleRepository , [ 'rev-parse' , '--show-toplevel' ] ) ;
482
482
483
483
// Keep trailing spaces which are part of the directory name
484
- const repoPath = path . normalize ( result . stdout . trimLeft ( ) . replace ( / [ \r \n ] + $ / , '' ) ) ;
484
+ const repositoryRootPath = path . normalize ( result . stdout . trimLeft ( ) . replace ( / [ \r \n ] + $ / , '' ) ) ;
485
485
486
486
if ( isWindows ) {
487
487
// On Git 2.25+ if you call `rev-parse --show-toplevel` on a mapped drive, instead of getting the mapped
488
488
// drive path back, you get the UNC path for the mapped drive. So we will try to normalize it back to the
489
489
// mapped drive path, if possible
490
- const repoUri = Uri . file ( repoPath ) ;
491
- const pathUri = Uri . file ( repositoryPath ) ;
490
+ const repoUri = Uri . file ( repositoryRootPath ) ;
491
+ const pathUri = Uri . file ( pathInsidePossibleRepository ) ;
492
492
if ( repoUri . authority . length !== 0 && pathUri . authority . length === 0 ) {
493
493
// eslint-disable-next-line local/code-no-look-behind-regex
494
494
const match = / (?< = ^ \/ ? ) ( [ a - z A - Z ] ) (? = : \/ ) / . exec ( pathUri . path ) ;
@@ -520,7 +520,18 @@ export class Git {
520
520
}
521
521
}
522
522
523
- return repoPath ;
523
+ // Handle symbolic links
524
+ // Git 2.31 added the `--path-format` flag to rev-parse which
525
+ // allows us to get the relative path of the repository root
526
+ if ( ! pathEquals ( pathInsidePossibleRepository , repositoryRootPath ) &&
527
+ ! isDescendant ( repositoryRootPath , pathInsidePossibleRepository ) &&
528
+ ! isDescendant ( pathInsidePossibleRepository , repositoryRootPath ) &&
529
+ this . compareGitVersionTo ( '2.31.0' ) !== - 1 ) {
530
+ const relativePathResult = await this . exec ( pathInsidePossibleRepository , [ 'rev-parse' , '--path-format=relative' , '--show-toplevel' , ] ) ;
531
+ return path . resolve ( pathInsidePossibleRepository , relativePathResult . stdout . trimLeft ( ) . replace ( / [ \r \n ] + $ / , '' ) ) ;
532
+ }
533
+
534
+ return repositoryRootPath ;
524
535
}
525
536
526
537
async getRepositoryDotGit ( repositoryPath : string ) : Promise < { path : string ; commonPath ?: string } > {
0 commit comments