@@ -7,6 +7,8 @@ import type { CancellationToken, OutputChannel } from 'vscode';
77import { env , Uri , window , workspace } from 'vscode' ;
88import { hrtime } from '@env/hrtime' ;
99import { GlyphChars } from '../../../constants' ;
10+ import type { GitFeature } from '../../../features' ;
11+ import { gitFeaturesByVersion } from '../../../features' ;
1012import type { GitCommandOptions , GitSpawnOptions } from '../../../git/commandOptions' ;
1113import { GitErrorHandling } from '../../../git/commandOptions' ;
1214import {
@@ -41,6 +43,7 @@ import { Logger } from '../../../system/logger';
4143import { slowCallWarningThreshold } from '../../../system/logger.constants' ;
4244import { getLoggableScopeBlockOverride , getLogScope } from '../../../system/logger.scope' ;
4345import { dirname , isAbsolute , isFolderGlob , joinPaths , normalizePath } from '../../../system/path' ;
46+ import { isPromise } from '../../../system/promise' ;
4447import { getDurationMilliseconds } from '../../../system/string' ;
4548import { compare , fromString } from '../../../system/version' ;
4649import { ensureGitTerminal } from '../../../terminal' ;
@@ -362,27 +365,29 @@ export class Git {
362365 return ( await this . getLocation ( ) ) . path ;
363366 }
364367
365- async version ( ) : Promise < string > {
366- return ( await this . getLocation ( ) ) . version ;
367- }
368+ async ensureSupports ( feature : GitFeature , prefix : string , suffix : string ) : Promise < void > {
369+ const version = gitFeaturesByVersion . get ( feature ) ;
370+ if ( version == null ) return ;
368371
369- async ensureGitVersion ( version : string , prefix : string , suffix : string ) : Promise < void > {
370- if ( await this . isAtLeastVersion ( version ) ) return ;
372+ const gitVersion = await this . version ( ) ;
373+ if ( compare ( fromString ( gitVersion ) , fromString ( version ) ) !== - 1 ) return ;
371374
372375 throw new Error (
373- `${ prefix } requires a newer version of Git (>= ${ version } ) than is currently installed (${ await this . version ( ) } ).${ suffix } ` ,
376+ `${ prefix } requires a newer version of Git (>= ${ version } ) than is currently installed (${ gitVersion } ).${ suffix } ` ,
374377 ) ;
375378 }
376379
377- async isAtLeastVersion ( minimum : string ) : Promise < boolean > {
378- const result = compare ( fromString ( await this . version ( ) ) , fromString ( minimum ) ) ;
379- return result !== - 1 ;
380- }
380+ supports ( feature : GitFeature ) : boolean | Promise < boolean > {
381+ const version = gitFeaturesByVersion . get ( feature ) ;
382+ if ( version == null ) return true ;
381383
382- maybeIsAtLeastVersion ( minimum : string ) : boolean | undefined {
383384 return this . _gitLocation != null
384- ? compare ( fromString ( this . _gitLocation . version ) , fromString ( minimum ) ) !== - 1
385- : undefined ;
385+ ? compare ( fromString ( this . _gitLocation . version ) , fromString ( version ) ) !== - 1
386+ : this . version ( ) . then ( v => compare ( fromString ( v ) , fromString ( version ) ) !== - 1 ) ;
387+ }
388+
389+ async version ( ) : Promise < string > {
390+ return ( await this . getLocation ( ) ) . version ;
386391 }
387392
388393 // Git commands
@@ -427,10 +432,10 @@ export class Git {
427432 }
428433
429434 // Ensure the version of Git supports the --ignore-revs-file flag, otherwise the blame will fail
430- let supportsIgnoreRevsFile = this . maybeIsAtLeastVersion ( '2.23 ') ;
431- if ( supportsIgnoreRevsFile === undefined ) {
432- supportsIgnoreRevsFile = await this . isAtLeastVersion ( '2.23' ) ;
433- }
435+ const supportsIgnoreRevsFileResult = this . supports ( 'git:ignoreRevsFile ') ;
436+ let supportsIgnoreRevsFile = isPromise ( supportsIgnoreRevsFileResult )
437+ ? await supportsIgnoreRevsFileResult
438+ : supportsIgnoreRevsFileResult ;
434439
435440 const ignoreRevsIndex = params . indexOf ( '--ignore-revs-file' ) ;
436441
@@ -825,7 +830,7 @@ export class Git {
825830 if ( options . force . withLease ) {
826831 params . push ( '--force-with-lease' ) ;
827832 if ( options . force . ifIncludes ) {
828- if ( await this . isAtLeastVersion ( '2.30.0 ') ) {
833+ if ( await this . supports ( 'git:push:force-if-includes ') ) {
829834 params . push ( '--force-if-includes' ) ;
830835 }
831836 }
@@ -1531,10 +1536,14 @@ export class Git {
15311536 }
15321537
15331538 if ( options ?. onlyStaged ) {
1534- if ( await this . isAtLeastVersion ( '2.35 ') ) {
1539+ if ( await this . supports ( 'git:stash:push:staged ') ) {
15351540 params . push ( '--staged' ) ;
15361541 } else {
1537- throw new Error ( 'Git version 2.35 or higher is required for --staged' ) ;
1542+ throw new Error (
1543+ `Git version ${ gitFeaturesByVersion . get (
1544+ 'git:stash:push:staged' ,
1545+ ) } }2.35 or higher is required for --staged`,
1546+ ) ;
15381547 }
15391548 }
15401549
@@ -1584,7 +1593,7 @@ export class Git {
15841593 '--branch' ,
15851594 '-u' ,
15861595 ] ;
1587- if ( await this . isAtLeastVersion ( '2.18 ') ) {
1596+ if ( await this . supports ( 'git:status:find-renames ') ) {
15881597 params . push (
15891598 `--find-renames${ options ?. similarityThreshold == null ? '' : `=${ options . similarityThreshold } %` } ` ,
15901599 ) ;
0 commit comments