@@ -10,6 +10,7 @@ import { GlyphChars } from '../../../constants';
1010import type { GitCommandOptions , GitSpawnOptions } from '../../../git/commandOptions' ;
1111import { GitErrorHandling } from '../../../git/commandOptions' ;
1212import {
13+ BlameIgnoreRevsFileBadRevisionError ,
1314 BlameIgnoreRevsFileError ,
1415 CherryPickError ,
1516 CherryPickErrorReason ,
@@ -35,7 +36,7 @@ import { parseGitTagsDefaultFormat } from '../../../git/parsers/tagParser';
3536import { splitAt } from '../../../system/array' ;
3637import { configuration } from '../../../system/configuration' ;
3738import { log } from '../../../system/decorators/log' ;
38- import { join } from '../../../system/iterable' ;
39+ import { count , join } from '../../../system/iterable' ;
3940import { Logger } from '../../../system/logger' ;
4041import { slowCallWarningThreshold } from '../../../system/logger.constants' ;
4142import { getLogScope } from '../../../system/logger.scope' ;
@@ -70,12 +71,13 @@ const textDecoder = new TextDecoder('utf8');
7071const rootSha = '4b825dc642cb6eb9a060e54bf8d69288fbee4904' ;
7172
7273export const GitErrors = {
73- badIgnoreRevsFile : / c o u l d n o t o p e n o b j e c t n a m e l i s t : ( .* ) \s / i,
7474 badRevision : / b a d r e v i s i o n ' ( .* ?) ' / i,
7575 cantLockRef : / c a n n o t l o c k r e f | u n a b l e t o u p d a t e l o c a l r e f / i,
7676 changesWouldBeOverwritten : / Y o u r l o c a l c h a n g e s t o t h e f o l l o w i n g f i l e s w o u l d b e o v e r w r i t t e n / i,
7777 commitChangesFirst : / P l e a s e , c o m m i t y o u r c h a n g e s b e f o r e y o u c a n / i,
7878 conflict : / ^ C O N F L I C T \( [ ^ ) ] + \) : \b / m,
79+ invalidObjectName : / i n v a l i d o b j e c t n a m e : ( .* ) \s / i,
80+ invalidObjectNameList : / c o u l d n o t o p e n o b j e c t n a m e l i s t : ( .* ) \s / i,
7981 noFastForward : / \( n o n - f a s t - f o r w a r d \) / i,
8082 noMergeBase : / n o m e r g e b a s e / i,
8183 noRemoteRepositorySpecified : / N o r e m o t e r e p o s i t o r y s p e c i f i e d \. / i,
@@ -386,20 +388,37 @@ export class Git {
386388 async blame (
387389 repoPath : string | undefined ,
388390 fileName : string ,
389- ref ?: string ,
390- options : { args ?: string [ ] | null ; ignoreWhitespace ?: boolean ; startLine ?: number ; endLine ?: number } = { } ,
391+ options ?: ( { ref : string | undefined ; contents ?: never } | { contents : string ; ref ?: never } ) & {
392+ args ?: string [ ] | null ;
393+ correlationKey ?: string ;
394+ ignoreWhitespace ?: boolean ;
395+ startLine ?: number ;
396+ endLine ?: number ;
397+ } ,
391398 ) {
392399 const [ file , root ] = splitPath ( fileName , repoPath , true ) ;
393400
394401 const params = [ 'blame' , '--root' , '--incremental' ] ;
395402
396- if ( options . ignoreWhitespace ) {
403+ if ( options ? .ignoreWhitespace ) {
397404 params . push ( '-w' ) ;
398405 }
399- if ( options . startLine != null && options . endLine != null ) {
406+ if ( options ? .startLine != null && options . endLine != null ) {
400407 params . push ( `-L ${ options . startLine } ,${ options . endLine } ` ) ;
401408 }
402- if ( options . args != null ) {
409+ if ( options ?. args != null ) {
410+ // See if the args contains a value like: `--ignore-revs-file <file>` or `--ignore-revs-file=<file>` to account for user error
411+ // If so split it up into two args
412+ const argIndex = options . args . findIndex (
413+ arg => arg !== '--ignore-revs-file' && arg . startsWith ( '--ignore-revs-file' ) ,
414+ ) ;
415+ if ( argIndex !== - 1 ) {
416+ const match = / ^ - - i g n o r e - r e v s - f i l e \s * = ? \s * ( .* ) $ / . exec ( options . args [ argIndex ] ) ;
417+ if ( match != null ) {
418+ options . args . splice ( argIndex , 1 , '--ignore-revs-file' , match [ 1 ] ) ;
419+ }
420+ }
421+
403422 params . push ( ...options . args ) ;
404423 }
405424
@@ -444,74 +463,43 @@ export class Git {
444463 }
445464
446465 let stdin ;
447- if ( ref ) {
448- if ( isUncommittedStaged ( ref ) ) {
466+ if ( options ?. contents != null ) {
467+ // Pipe the blame contents to stdin
468+ params . push ( '--contents' , '-' ) ;
469+
470+ stdin = options . contents ;
471+ } else if ( options ?. ref ) {
472+ if ( isUncommittedStaged ( options . ref ) ) {
449473 // Pipe the blame contents to stdin
450474 params . push ( '--contents' , '-' ) ;
451475
452476 // Get the file contents for the staged version using `:`
453477 stdin = await this . show < string > ( repoPath , fileName , ':' ) ;
454478 } else {
455- params . push ( ref ) ;
479+ params . push ( options . ref ) ;
456480 }
457481 }
458482
459- try {
460- const blame = await this . git < string > ( { cwd : root , stdin : stdin } , ...params , '--' , file ) ;
461- return blame ;
462- } catch ( ex ) {
463- // Since `-c blame.ignoreRevsFile=` doesn't seem to work (unlike as the docs suggest), try to detect the error and throw a more helpful one
464- const match = GitErrors . badIgnoreRevsFile . exec ( ex . message ) ;
465- if ( match != null ) {
466- throw new BlameIgnoreRevsFileError ( match [ 1 ] , ex ) ;
467- }
468- throw ex ;
469- }
470- }
471-
472- async blame__contents (
473- repoPath : string | undefined ,
474- fileName : string ,
475- contents : string ,
476- options : {
477- args ?: string [ ] | null ;
478- correlationKey ?: string ;
479- ignoreWhitespace ?: boolean ;
480- startLine ?: number ;
481- endLine ?: number ;
482- } = { } ,
483- ) {
484- const [ file , root ] = splitPath ( fileName , repoPath , true ) ;
485-
486- const params = [ 'blame' , '--root' , '--incremental' ] ;
487-
488- if ( options . ignoreWhitespace ) {
489- params . push ( '-w' ) ;
490- }
491- if ( options . startLine != null && options . endLine != null ) {
492- params . push ( `-L ${ options . startLine } ,${ options . endLine } ` ) ;
493- }
494- if ( options . args != null ) {
495- params . push ( ...options . args ) ;
496- }
497-
498- // Pipe the blame contents to stdin
499- params . push ( '--contents' , '-' ) ;
500-
501483 try {
502484 const blame = await this . git < string > (
503- { cwd : root , stdin : contents , correlationKey : options . correlationKey } ,
485+ { cwd : root , stdin : stdin , correlationKey : options ? .correlationKey } ,
504486 ...params ,
505487 '--' ,
506488 file ,
507489 ) ;
508490 return blame ;
509491 } catch ( ex ) {
510492 // Since `-c blame.ignoreRevsFile=` doesn't seem to work (unlike as the docs suggest), try to detect the error and throw a more helpful one
511- const match = GitErrors . badIgnoreRevsFile . exec ( ex . message ) ;
493+ let match = GitErrors . invalidObjectNameList . exec ( ex . message ) ;
512494 if ( match != null ) {
513495 throw new BlameIgnoreRevsFileError ( match [ 1 ] , ex ) ;
514496 }
497+
498+ match = GitErrors . invalidObjectName . exec ( ex . message ) ;
499+ if ( match != null ) {
500+ throw new BlameIgnoreRevsFileBadRevisionError ( match [ 1 ] , ex ) ;
501+ }
502+
515503 throw ex ;
516504 }
517505 }
0 commit comments