@@ -37,6 +37,7 @@ import {
3737 getBranchNameWithoutRemote ,
3838 getRemoteNameFromBranchName ,
3939} from '../../../../git/utils/branch.utils' ;
40+ import { getChangedFilesCount } from '../../../../git/utils/commit.utils' ;
4041import { createReference } from '../../../../git/utils/reference.utils' ;
4142import { isUncommittedStaged } from '../../../../git/utils/revision.utils' ;
4243import { getTagId } from '../../../../git/utils/tag.utils' ;
@@ -135,14 +136,13 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
135136
136137 // TODO@eamodio this is insanity -- there *HAS* to be a better way to get git log to return stashes
137138 const gitStash = getSettledValue ( stashResult ) ;
138- const { stdin, stashes } = convertStashesToStdin ( gitStash ?. stashes ) ;
139+ const { stdin, stashes, remappedIds } = convertStashesToStdin ( gitStash ?. stashes ) ;
139140
140141 const useAvatars = configuration . get ( 'graph.avatars' , undefined , true ) ;
141142
142143 const avatars = new Map < string , string > ( ) ;
143144 const ids = new Set < string > ( ) ;
144145 const reachableFromHEAD = new Set < string > ( ) ;
145- const remappedIds = new Map < string , string > ( ) ;
146146 const rowStats : GitGraphRowsStats = new Map < string , GitGraphRowStats > ( ) ;
147147 let pendingRowsStatsCount = 0 ;
148148 let iterations = 0 ;
@@ -208,6 +208,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
208208 let remote : GitRemote | undefined ;
209209 let remoteBranchId : string ;
210210 let remoteName : string ;
211+ let shaOrRemapped : string | undefined ;
211212 let stash : GitStashCommit | undefined ;
212213 let tagId : string ;
213214 let tagName : string ;
@@ -233,9 +234,11 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
233234 if ( ids . has ( commit . sha ) ) continue ;
234235
235236 total ++ ;
236- if ( remappedIds . has ( commit . sha ) ) continue ;
237+ shaOrRemapped = remappedIds . get ( commit . sha ) ;
238+ if ( shaOrRemapped && ids . has ( shaOrRemapped ) ) continue ;
239+ shaOrRemapped ??= commit . sha ;
237240
238- ids . add ( commit . sha ) ;
241+ ids . add ( shaOrRemapped ) ;
239242
240243 refHeads = [ ] ;
241244 refRemoteHeads = [ ] ;
@@ -279,7 +282,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
279282
280283 if ( tip . startsWith ( 'HEAD' ) ) {
281284 head = true ;
282- reachableFromHEAD . add ( commit . sha ) ;
285+ reachableFromHEAD . add ( shaOrRemapped ) ;
283286
284287 if ( tip !== 'HEAD' ) {
285288 tip = tip . substring ( 8 ) ;
@@ -424,56 +427,67 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
424427 }
425428 }
426429
427- stash = gitStash ?. stashes . get ( commit . sha ) ;
428-
429430 parents = commit . parents ? commit . parents . split ( ' ' ) : [ ] ;
430- if ( reachableFromHEAD . has ( commit . sha ) ) {
431+ if ( reachableFromHEAD . has ( shaOrRemapped ) ) {
431432 for ( parent of parents ) {
432433 reachableFromHEAD . add ( parent ) ;
433434 }
434435 }
435436
436- // Remove the second & third parent, if exists, from each stash commit as it is a Git implementation for the index and untracked files
437- if ( stash != null && parents . length > 1 ) {
438- // Remap the "index commit" (e.g. contains staged files) of the stash
439- remappedIds . set ( parents [ 1 ] , commit . sha ) ;
440- // Remap the "untracked commit" (e.g. contains untracked files) of the stash
441- if ( parents . length > 2 ) {
442- remappedIds . set ( parents [ 2 ] , commit . sha ) ;
443- }
444- parents . splice ( 1 , 2 ) ;
445- }
446-
447- if ( stash == null && ! avatars . has ( commit . authorEmail ) ) {
448- avatarUri = getCachedAvatarUri ( commit . authorEmail ) ;
449- if ( avatarUri != null ) {
450- avatars . set ( commit . authorEmail , avatarUri . toString ( true ) ) ;
451- }
452- }
453-
454- isCurrentUser = isUserMatch ( currentUser , commit . author , commit . authorEmail ) ;
455-
437+ stash = gitStash ?. stashes . get ( shaOrRemapped ) ;
456438 if ( stash != null ) {
457439 contexts . row = serializeWebviewItemContext < GraphItemRefContext > ( {
458440 webviewItem : 'gitlens:stash' ,
459441 webviewItemValue : {
460442 type : 'stash' ,
461- ref : createReference ( commit . sha , repoPath , {
443+ ref : createReference ( shaOrRemapped , repoPath , {
462444 refType : 'stash' ,
463445 name : stash . name ,
464446 message : stash . message ,
465447 number : stash . stashNumber ,
466448 } ) ,
467449 } ,
468450 } ) ;
451+
452+ rows . push ( {
453+ sha : shaOrRemapped ,
454+ // Always only return the first parent for stashes, as it is a Git implementation for the index and untracked files
455+ parents : parents . slice ( 0 , 1 ) ,
456+ author : 'You' ,
457+ email : commit . authorEmail ,
458+ date : Number ( ordering === 'author-date' ? commit . authorDate : commit . committerDate ) * 1000 ,
459+ message : emojify ( stash . message ?? commit . message . trim ( ) ) ,
460+ type : 'stash-node' ,
461+ heads : refHeads ,
462+ remotes : refRemoteHeads ,
463+ tags : refTags ,
464+ contexts : contexts ,
465+ } ) ;
466+
467+ if ( stash . stats != null ) {
468+ rowStats . set ( shaOrRemapped , {
469+ files : getChangedFilesCount ( stash . stats . files ) ,
470+ additions : stash . stats . additions ,
471+ deletions : stash . stats . deletions ,
472+ } ) ;
473+ }
469474 } else {
475+ isCurrentUser = isUserMatch ( currentUser , commit . author , commit . authorEmail ) ;
476+
477+ if ( ! avatars . has ( commit . authorEmail ) ) {
478+ avatarUri = getCachedAvatarUri ( commit . authorEmail ) ;
479+ if ( avatarUri != null ) {
480+ avatars . set ( commit . authorEmail , avatarUri . toString ( true ) ) ;
481+ }
482+ }
483+
470484 contexts . row = serializeWebviewItemContext < GraphItemRefContext > ( {
471485 webviewItem : `gitlens:commit${ head ? '+HEAD' : '' } ${
472- reachableFromHEAD . has ( commit . sha ) ? '+current' : ''
486+ reachableFromHEAD . has ( shaOrRemapped ) ? '+current' : ''
473487 } `,
474488 webviewItemValue : {
475489 type : 'commit' ,
476- ref : createReference ( commit . sha , repoPath , {
490+ ref : createReference ( shaOrRemapped , repoPath , {
477491 refType : 'revision' ,
478492 message : commit . message ,
479493 } ) ,
@@ -490,25 +504,24 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
490504 current : isCurrentUser ,
491505 } ,
492506 } ) ;
493- }
494507
495- rows . push ( {
496- sha : commit . sha ,
497- parents : onlyFollowFirstParent ? [ parents [ 0 ] ] : parents ,
498- author : isCurrentUser ? 'You' : commit . author ,
499- email : commit . authorEmail ,
500- date : Number ( ordering === 'author-date' ? commit . authorDate : commit . committerDate ) * 1000 ,
501- message : emojify ( commit . message . trim ( ) ) ,
502- // TODO: review logic for stash, wip, etc
503- type : stash != null ? 'stash-node' : parents . length > 1 ? 'merge-node' : 'commit-node' ,
504- heads : refHeads ,
505- remotes : refRemoteHeads ,
506- tags : refTags ,
507- contexts : contexts ,
508- } ) ;
508+ rows . push ( {
509+ sha : shaOrRemapped ,
510+ parents : onlyFollowFirstParent ? parents . slice ( 0 , 1 ) : parents ,
511+ author : isCurrentUser ? 'You' : commit . author ,
512+ email : commit . authorEmail ,
513+ date : Number ( ordering === 'author-date' ? commit . authorDate : commit . committerDate ) * 1000 ,
514+ message : emojify ( commit . message . trim ( ) ) ,
515+ type : parents . length > 1 ? 'merge-node' : 'commit-node' ,
516+ heads : refHeads ,
517+ remotes : refRemoteHeads ,
518+ tags : refTags ,
519+ contexts : contexts ,
520+ } ) ;
509521
510- if ( commit . stats != null ) {
511- rowStats . set ( commit . sha , commit . stats ) ;
522+ if ( commit . stats != null ) {
523+ rowStats . set ( shaOrRemapped , commit . stats ) ;
524+ }
512525 }
513526 }
514527
@@ -541,9 +554,14 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
541554 ) ;
542555
543556 if ( statsResult . stdout ) {
544- const commitStats = statsParser . parse ( statsResult . stdout ) ;
545- for ( const stat of commitStats ) {
546- rowStats . set ( stat . sha , stat . stats ) ;
557+ let statShaOrRemapped ;
558+ for ( const stat of statsParser . parse ( statsResult . stdout ) ) {
559+ statShaOrRemapped = remappedIds . get ( stat . sha ) ?? stat . sha ;
560+
561+ // If we already have the stats for this sha, skip it (e.g. stashes)
562+ if ( rowStats . has ( statShaOrRemapped ) ) continue ;
563+
564+ rowStats . set ( statShaOrRemapped , stat . stats ) ;
547565 }
548566 }
549567 } finally {
@@ -563,7 +581,6 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
563581 avatars : avatars ,
564582 ids : ids ,
565583 includes : options ?. include ,
566- remappedIds : remappedIds ,
567584 branches : branchMap ,
568585 remotes : remoteMap ,
569586 downstreams : downstreamMap ,
@@ -635,13 +652,16 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
635652
636653 let stashes : Map < string , GitStashCommit > | undefined ;
637654 let stdin : string | undefined ;
655+ let remappedIds : Map < string , string > ;
638656
639657 if ( shas ?. size ) {
640658 stdin = join ( shas , '\n' ) ;
641659 args . push ( '--no-walk' ) ;
660+
661+ remappedIds = new Map ( ) ;
642662 } else {
643663 // TODO@eamodio this is insanity -- there *HAS* to be a better way to get git log to return stashes
644- ( { stdin, stashes } = convertStashesToStdin (
664+ ( { stdin, stashes, remappedIds } = convertStashesToStdin (
645665 await this . provider . stash ?. getStash ( repoPath , undefined , cancellation ) ,
646666 ) ) ;
647667 }
@@ -696,6 +716,7 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
696716
697717 let count = 0 ;
698718 let hasMore = false ;
719+ let sha ;
699720 const stashesOnly = filters . type === 'stash' ;
700721
701722 for await ( const r of parser . parseAsync ( stream ) ) {
@@ -707,11 +728,12 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
707728 }
708729
709730 count ++ ;
710- if ( results . has ( r . sha ) || ( stashesOnly && ! stashes ?. has ( r . sha ) ) ) {
731+ sha = remappedIds . get ( r . sha ) ?? r . sha ;
732+ if ( results . has ( sha ) || ( stashesOnly && ! stashes ?. has ( sha ) ) ) {
711733 continue ;
712734 }
713735
714- results . set ( r . sha , {
736+ results . set ( sha , {
715737 i : results . size ,
716738 date : Number ( options ?. ordering === 'author-date' ? r . authorDate : r . committerDate ) * 1000 ,
717739 } ) ;
0 commit comments