@@ -718,8 +718,10 @@ public async Task GetSourceAsync(
718718 await RemoveGitConfig ( executionContext , gitCommandManager , targetPath , $ "http.proxy", string . Empty ) ;
719719 }
720720
721- List < string > additionalFetchArgs = new List < string > ( ) ;
722- List < string > additionalLfsFetchArgs = new List < string > ( ) ;
721+ var additionalFetchFilterOptions = ParseFetchFilterOptions ( executionContext , fetchFilter ) ;
722+ var additionalFetchArgs = new List < string > ( ) ;
723+ var additionalLfsFetchArgs = new List < string > ( ) ;
724+ var additionalCheckoutArgs = new List < string > ( ) ;
723725
724726 // Force Git to HTTP/1.1. Otherwise IIS will reject large pushes to Azure Repos due to the large content-length header
725727 // This is caused by these header limits - https://docs.microsoft.com/en-us/iis/configuration/system.webserver/security/requestfiltering/requestlimits/headerlimits/
@@ -738,6 +740,11 @@ public async Task GetSourceAsync(
738740 string configKey = "http.extraheader" ;
739741 string args = ComposeGitArgs ( executionContext , gitCommandManager , configKey , username , password , useBearerAuthType ) ;
740742 additionalFetchArgs . Add ( args ) ;
743+
744+ if ( additionalFetchFilterOptions . Any ( ) && AgentKnobs . AddForceCredentialsToGitCheckout . GetValue ( executionContext ) . AsBoolean ( ) )
745+ {
746+ additionalCheckoutArgs . Add ( args ) ;
747+ }
741748 }
742749 else
743750 {
@@ -899,7 +906,7 @@ public async Task GetSourceAsync(
899906 }
900907 }
901908
902- int exitCode_fetch = await gitCommandManager . GitFetch ( executionContext , targetPath , "origin" , fetchDepth , fetchFilter , fetchTags , additionalFetchSpecs , string . Join ( " " , additionalFetchArgs ) , cancellationToken ) ;
909+ int exitCode_fetch = await gitCommandManager . GitFetch ( executionContext , targetPath , "origin" , fetchDepth , additionalFetchFilterOptions , fetchTags , additionalFetchSpecs , string . Join ( " " , additionalFetchArgs ) , cancellationToken ) ;
903910 if ( exitCode_fetch != 0 )
904911 {
905912 throw new InvalidOperationException ( $ "Git fetch failed with exit code: { exitCode_fetch } ") ;
@@ -911,7 +918,7 @@ public async Task GetSourceAsync(
911918 if ( fetchByCommit && ! string . IsNullOrEmpty ( sourceVersion ) )
912919 {
913920 List < string > commitFetchSpecs = new List < string > ( ) { $ "+{ sourceVersion } " } ;
914- exitCode_fetch = await gitCommandManager . GitFetch ( executionContext , targetPath , "origin" , fetchDepth , fetchFilter , fetchTags , commitFetchSpecs , string . Join ( " " , additionalFetchArgs ) , cancellationToken ) ;
921+ exitCode_fetch = await gitCommandManager . GitFetch ( executionContext , targetPath , "origin" , fetchDepth , additionalFetchFilterOptions , fetchTags , commitFetchSpecs , string . Join ( " " , additionalFetchArgs ) , cancellationToken ) ;
915922 if ( exitCode_fetch != 0 )
916923 {
917924 throw new InvalidOperationException ( $ "Git fetch failed with exit code: { exitCode_fetch } ") ;
@@ -963,7 +970,7 @@ public async Task GetSourceAsync(
963970 }
964971
965972 // Finally, checkout the sourcesToBuild (if we didn't find a valid git object this will throw)
966- int exitCode_checkout = await gitCommandManager . GitCheckout ( executionContext , targetPath , sourcesToBuild , cancellationToken ) ;
973+ int exitCode_checkout = await gitCommandManager . GitCheckout ( executionContext , targetPath , sourcesToBuild , string . Join ( " " , additionalCheckoutArgs ) , cancellationToken ) ;
967974 if ( exitCode_checkout != 0 )
968975 {
969976 // local repository is shallow repository, checkout may fail due to lack of commits history.
@@ -1374,6 +1381,59 @@ private async Task<bool> IsRepositoryOriginUrlMatch(AgentTaskPluginExecutionCont
13741381 }
13751382 }
13761383
1384+ private IEnumerable < string > ParseFetchFilterOptions ( AgentTaskPluginExecutionContext context , string fetchFilter )
1385+ {
1386+ if ( ! AgentKnobs . UseFetchFilterInCheckoutTask . GetValue ( context ) . AsBoolean ( ) )
1387+ {
1388+ return Enumerable . Empty < string > ( ) ;
1389+ }
1390+
1391+ if ( string . IsNullOrEmpty ( fetchFilter ) )
1392+ {
1393+ return Enumerable . Empty < string > ( ) ;
1394+ }
1395+
1396+ // parse filter and only include valid options
1397+ var filters = new List < string > ( ) ;
1398+ var splitFilter = fetchFilter . Split ( '+' ) . Where ( filter => ! string . IsNullOrWhiteSpace ( filter ) ) . ToList ( ) ;
1399+
1400+ foreach ( string filter in splitFilter )
1401+ {
1402+ var parsedFilter = filter . Split ( ':' )
1403+ . Where ( filter => ! string . IsNullOrWhiteSpace ( filter ) )
1404+ . Select ( filter => filter . Trim ( ) )
1405+ . ToList ( ) ;
1406+
1407+ if ( parsedFilter . Count == 2 )
1408+ {
1409+ switch ( parsedFilter [ 0 ] . ToLower ( ) )
1410+ {
1411+ case "tree" :
1412+ // currently only supporting treeless filter
1413+ if ( int . TryParse ( parsedFilter [ 1 ] , out int treeSize ) && treeSize == 0 )
1414+ {
1415+ filters . Add ( $ "{ parsedFilter [ 0 ] } :{ treeSize } ") ;
1416+ }
1417+ break ;
1418+
1419+ case "blob" :
1420+ // currently only supporting blobless filter
1421+ if ( parsedFilter [ 1 ] . Equals ( "none" , StringComparison . OrdinalIgnoreCase ) )
1422+ {
1423+ filters . Add ( $ "{ parsedFilter [ 0 ] } :{ parsedFilter [ 1 ] } ") ;
1424+ }
1425+ break ;
1426+
1427+ default :
1428+ // either invalid or unsupported git object
1429+ break ;
1430+ }
1431+ }
1432+ }
1433+
1434+ return filters ;
1435+ }
1436+
13771437 private async Task RunGitStatusIfSystemDebug ( AgentTaskPluginExecutionContext executionContext , GitCliManager gitCommandManager , string targetPath )
13781438 {
13791439 if ( executionContext . IsSystemDebugTrue ( ) )
0 commit comments