@@ -30,7 +30,7 @@ import {
3030}  from  '../../../../git/parsers/logParser' ; 
3131import  type  {  GitGraphSearch ,  GitGraphSearchResultData ,  GitGraphSearchResults  }  from  '../../../../git/search' ; 
3232import  {  getSearchQueryComparisonKey ,  parseSearchQueryCommand  }  from  '../../../../git/search' ; 
33- import  {  getDefaultBranchName ,  isBranchStarred  }  from  '../../../../git/utils/-webview/branch.utils' ; 
33+ import  {  getBranchMergeBaseAndCommonCommit ,  isBranchStarred  }  from  '../../../../git/utils/-webview/branch.utils' ; 
3434import  {  getRemoteIconUri  }  from  '../../../../git/utils/-webview/icons' ; 
3535import  {  groupWorktreesByBranch  }  from  '../../../../git/utils/-webview/worktree.utils' ; 
3636import  { 
@@ -349,7 +349,10 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
349349							branchId  =  branch ?. id  ??  getBranchId ( repoPath ,  false ,  tip ) ; 
350350
351351							// Check if branch has commits that can be recomposed and get merge base 
352- 							const  mergeBase  =  await  this . getMergeBase ( branch ,  repoPath ) ; 
352+ 							const  mergeBaseResult  = 
353+ 								branch  &&  ( await  getBranchMergeBaseAndCommonCommit ( this . container ,  branch ) ) ; 
354+ 							const  isRecomposable  =  Boolean ( mergeBaseResult  &&  mergeBaseResult . commit  !==  branch ?. sha ) ; 
355+ 							const  mergeBase  =  isRecomposable  ? mergeBaseResult  : undefined ; 
353356
354357							context  =  { 
355358								webviewItem : `gitlens:branch${ head  ? '+current'  : '' } ${  
@@ -625,74 +628,6 @@ export class GraphGitSubProvider implements GitGraphSubProvider {
625628		return  getCommitsForGraphCore . call ( this ,  defaultLimit ,  selectSha ,  undefined ,  cancellation ) ; 
626629	} 
627630
628- 	private  async  getMergeBase ( 
629- 		branch : GitBranch  |  undefined , 
630- 		repoPath : string , 
631- 	) : Promise < {  commit : string ;  branch : string ;  remote : boolean  }  |  undefined >  { 
632- 		if  ( ! branch  ||  branch . remote )  return  undefined ; 
633- 
634- 		try  { 
635- 			const  upstreamName  =  branch . upstream ?. name ; 
636- 			const  svc  =  this . container . git . getRepositoryService ( repoPath ) ; 
637- 
638- 			// Get stored merge target configurations 
639- 			const  [ targetBranchResult ,  mergeBaseResult ,  defaultBranchResult ]  =  await  Promise . allSettled ( [ 
640- 				svc . branches . getStoredMergeTargetBranchName ?.( branch . name ) , 
641- 				svc . branches . getBaseBranchName ?.( branch . name ) , 
642- 				getDefaultBranchName ( this . container ,  branch . repoPath ,  branch . name ) , 
643- 			] ) ; 
644- 			const  targetBranch  =  getSettledValue ( targetBranchResult ) ; 
645- 			const  validTargetBranch  =  targetBranch  &&  targetBranch  !==  upstreamName  ? targetBranch  : undefined ; 
646- 			const  mergeBase  =  getSettledValue ( mergeBaseResult )  ||  getSettledValue ( defaultBranchResult ) ; 
647- 			const  validMergeBase  =  mergeBase  &&  mergeBase  !==  upstreamName  ? mergeBase  : undefined ; 
648- 
649- 			// Select target with most recent common commit (closest to branch tip) 
650- 			const  validTargets  =  [ validTargetBranch ,  validMergeBase ] ; 
651- 			const  recentMergeBase  =  await  this . selectMostRecentMergeBase ( branch . name ,  validTargets ,  svc ) ; 
652- 
653- 			const  isRecomposable  =  Boolean ( recentMergeBase  &&  recentMergeBase . commit  !==  branch . sha ) ; 
654- 			return  isRecomposable  ? recentMergeBase  : undefined ; 
655- 		}  catch  { 
656- 			// If we can't determine, assume not recomposable 
657- 			return  undefined ; 
658- 		} 
659- 	} 
660- 
661- 	private  async  selectMostRecentMergeBase ( 
662- 		branchName : string , 
663- 		targets : ( string  |  undefined ) [ ] , 
664- 		svc : ReturnType < typeof  this . container . git . getRepositoryService > , 
665- 	) : Promise < {  commit : string ;  branch : string ;  remote : boolean  }  |  undefined >  { 
666- 		const  isString  =  ( t : string  |  undefined ) : t  is string  =>  Boolean ( t ) ; 
667- 		const  mergeBaseResults  =  await  Promise . allSettled ( 
668- 			targets . filter ( isString ) . map ( async  target  =>  { 
669- 				const  commit  =  await  svc . refs . getMergeBase ( branchName ,  target ) ; 
670- 				return  { 
671- 					commit : commit , 
672- 					branch : target , 
673- 				} ; 
674- 			} ) , 
675- 		) ; 
676- 		const  mergeBases  =  mergeBaseResults 
677- 			. map ( result  =>  getSettledValue ( result ) ) 
678- 			. filter ( ( r ) : r  is {  commit : string ;  branch : string ;  remote : boolean  }  =>  isString ( r ?. commit ) ) ; 
679- 
680- 		if  ( mergeBases . length  ===  0 )  return  undefined ; 
681- 
682- 		let  mostRecentMergeBase  =  mergeBases [ 0 ] ; 
683- 		for  ( let  i  =  1 ;  i  <  mergeBases . length ;  i ++ )  { 
684- 			const  isCurrentMoreRecent  =  await  svc . commits . isAncestorOf ( 
685- 				mostRecentMergeBase ?. commit , 
686- 				mergeBases [ i ] . commit , 
687- 			) ; 
688- 			if  ( isCurrentMoreRecent )  { 
689- 				mostRecentMergeBase  =  mergeBases [ i ] ; 
690- 			} 
691- 		} 
692- 
693- 		return  mostRecentMergeBase ; 
694- 	} 
695- 
696631	@log < GraphGitSubProvider [ 'searchGraph' ] > ( { 
697632		args : { 
698633			1 : s  => 
0 commit comments