@@ -134,7 +134,7 @@ public void RefreshAll()
134134 } ;
135135
136136 // Fire and forget - these will complete asynchronously
137- Task . WhenAll ( parallelTasks ) . ContinueWith ( t =>
137+ Task . WhenAll ( parallelTasks ) . ContinueWith ( async t =>
138138 {
139139 if ( t . IsFaulted )
140140 {
@@ -149,20 +149,32 @@ public void RefreshAll()
149149 {
150150 var totalTime = Models . PerformanceMonitor . StopTimer ( "RefreshAll" ) ;
151151 System . Diagnostics . Debug . WriteLine ( $ "[PERF] RefreshAll completed in { totalTime } ms") ;
152-
152+
153153 // Log summary periodically
154154 if ( totalTime > 0 && Models . PerformanceMonitor . GetAverageTime ( "RefreshAll" ) > 0 )
155155 {
156156 var summary = Models . PerformanceMonitor . GetPerformanceSummary ( ) ;
157157 System . Diagnostics . Debug . WriteLine ( summary ) ;
158158 }
159+
160+ // Load GitFlow configuration after branches are loaded
161+ await LoadGitFlowConfigAsync ( ) ;
162+
163+ // Update GitFlow branches if enabled
164+ if ( _settings != null && _settings . ShowGitFlowInSidebar && _branches != null )
165+ {
166+ var localBranches = _branches . Where ( b => b . IsLocal && ! b . IsDetachedHead ) . ToList ( ) ;
167+ ExecuteOnUIThread ( ( ) =>
168+ {
169+ UpdateGitFlowBranches ( localBranches ) ;
170+ } ) ;
171+ }
159172 }
160173 } ) ;
161174
162175 Task . Run ( async ( ) =>
163176 {
164177 await LoadIssueTrackersAsync ( ) ;
165- await LoadGitFlowConfigAsync ( ) ;
166178 } ) ;
167179 }
168180
@@ -217,7 +229,30 @@ public void RefreshBranches()
217229 }
218230 LocalBranchesCount = localBranchesCount ;
219231
220- UpdateGitFlowBranches ( localBranches ) ;
232+ // Check and auto-configure GitFlow if structure is detected
233+ CheckAndAutoConfigureGitFlow ( localBranches ) ;
234+ } ) ;
235+
236+ // Load GitFlow configuration after auto-configuration
237+ await LoadGitFlowConfigAsync ( ) . ConfigureAwait ( false ) ;
238+
239+ ExecuteOnUIThread ( ( ) =>
240+ {
241+ // Get local branches again for GitFlow update
242+ var localBranches = new List < Models . Branch > ( ) ;
243+ foreach ( var b in branches )
244+ {
245+ if ( b . IsLocal && ! b . IsDetachedHead )
246+ {
247+ localBranches . Add ( b ) ;
248+ }
249+ }
250+
251+ // Update GitFlow branches only if GitFlow display is enabled
252+ if ( _settings != null && _settings . ShowGitFlowInSidebar )
253+ {
254+ UpdateGitFlowBranches ( localBranches ) ;
255+ }
221256 UpdateWorkingCopyRemotesInfo ( remotes ) ;
222257 UpdatePendingPullPushState ( ) ;
223258 } ) ;
@@ -475,18 +510,20 @@ private void UpdateGitFlowBranches(List<Models.Branch> localBranches)
475510 {
476511 try
477512 {
478- if ( IsGitFlowEnabled ( ) )
513+ // Check if we should update GitFlow branches
514+ // Don't require IsGitFlowEnabled() here as it checks for branch existence which might not be loaded yet
515+ if ( GitFlow != null && GitFlow . IsValid && _settings != null && _settings . ShowGitFlowInSidebar )
479516 {
480517 var groups = new List < Models . GitFlowBranchGroup > ( ) ;
481518 var gitFlowBranches = new List < Models . Branch > ( ) ;
482-
519+
483520 var featureGroup = new Models . GitFlowBranchGroup { Type = Models . GitFlowBranchType . Feature , Name = "Features" } ;
484521 var releaseGroup = new Models . GitFlowBranchGroup { Type = Models . GitFlowBranchType . Release , Name = "Releases" } ;
485522 var hotfixGroup = new Models . GitFlowBranchGroup { Type = Models . GitFlowBranchType . Hotfix , Name = "Hotfixes" } ;
486-
523+
487524 foreach ( var branch in localBranches )
488525 {
489- var type = GetGitFlowType ( branch ) ;
526+ var type = GetGitFlowTypeForBranch ( branch ) ;
490527 switch ( type )
491528 {
492529 case Models . GitFlowBranchType . Feature :
@@ -503,14 +540,14 @@ private void UpdateGitFlowBranches(List<Models.Branch> localBranches)
503540 break ;
504541 }
505542 }
506-
543+
507544 if ( featureGroup . Branches . Count > 0 )
508545 groups . Add ( featureGroup ) ;
509546 if ( releaseGroup . Branches . Count > 0 )
510547 groups . Add ( releaseGroup ) ;
511548 if ( hotfixGroup . Branches . Count > 0 )
512549 groups . Add ( hotfixGroup ) ;
513-
550+
514551 GitFlowBranchGroups = groups ;
515552 GitFlowBranches = gitFlowBranches ;
516553 }
@@ -528,6 +565,24 @@ private void UpdateGitFlowBranches(List<Models.Branch> localBranches)
528565 }
529566 }
530567
568+ private Models . GitFlowBranchType GetGitFlowTypeForBranch ( Models . Branch b )
569+ {
570+ if ( GitFlow == null || ! GitFlow . IsValid )
571+ return Models . GitFlowBranchType . None ;
572+
573+ var name = b . Name ;
574+ if ( name . StartsWith ( GitFlow . FeaturePrefix , StringComparison . Ordinal ) )
575+ return Models . GitFlowBranchType . Feature ;
576+ if ( name . StartsWith ( GitFlow . ReleasePrefix , StringComparison . Ordinal ) )
577+ return Models . GitFlowBranchType . Release ;
578+ if ( name . StartsWith ( GitFlow . HotfixPrefix , StringComparison . Ordinal ) )
579+ return Models . GitFlowBranchType . Hotfix ;
580+ if ( ! string . IsNullOrEmpty ( GitFlow . SupportPrefix ) && name . StartsWith ( GitFlow . SupportPrefix , StringComparison . Ordinal ) )
581+ return Models . GitFlowBranchType . Support ;
582+
583+ return Models . GitFlowBranchType . None ;
584+ }
585+
531586 /// <summary>
532587 /// Updates working copy remotes information
533588 /// </summary>
@@ -601,18 +656,141 @@ private async Task LoadGitFlowConfigAsync()
601656 var config = await new Commands . Config ( _fullpath ) . ReadAllAsync ( ) . ConfigureAwait ( false ) ;
602657 _hasAllowedSignersFile = config . TryGetValue ( "gpg.ssh.allowedSignersFile" , out var allowedSignersFile ) && ! string . IsNullOrEmpty ( allowedSignersFile ) ;
603658
604- if ( config . TryGetValue ( "gitflow.branch.master" , out var masterName ) )
605- GitFlow . Master = masterName ;
606- if ( config . TryGetValue ( "gitflow.branch.develop" , out var developName ) )
607- GitFlow . Develop = developName ;
608- if ( config . TryGetValue ( "gitflow.prefix.feature" , out var featurePrefix ) )
609- GitFlow . FeaturePrefix = featurePrefix ;
610- if ( config . TryGetValue ( "gitflow.prefix.release" , out var releasePrefix ) )
611- GitFlow . ReleasePrefix = releasePrefix ;
612- if ( config . TryGetValue ( "gitflow.prefix.hotfix" , out var hotfixPrefix ) )
613- GitFlow . HotfixPrefix = hotfixPrefix ;
659+ // Check if GitFlow is configured explicitly
660+ bool hasGitFlowConfig = config . Keys . Any ( k => k . StartsWith ( "gitflow." ) ) ;
661+
662+ if ( hasGitFlowConfig )
663+ {
664+ // Load explicit GitFlow configuration
665+ if ( config . TryGetValue ( "gitflow.branch.master" , out var masterName ) )
666+ GitFlow . Master = masterName ;
667+ if ( config . TryGetValue ( "gitflow.branch.develop" , out var developName ) )
668+ GitFlow . Develop = developName ;
669+ if ( config . TryGetValue ( "gitflow.prefix.feature" , out var featurePrefix ) )
670+ GitFlow . FeaturePrefix = featurePrefix ;
671+ if ( config . TryGetValue ( "gitflow.prefix.release" , out var releasePrefix ) )
672+ GitFlow . ReleasePrefix = releasePrefix ;
673+ if ( config . TryGetValue ( "gitflow.prefix.hotfix" , out var hotfixPrefix ) )
674+ GitFlow . HotfixPrefix = hotfixPrefix ;
675+ if ( config . TryGetValue ( "gitflow.prefix.support" , out var supportPrefix ) )
676+ GitFlow . SupportPrefix = supportPrefix ;
677+ if ( config . TryGetValue ( "gitflow.prefix.versiontag" , out var versionTagPrefix ) )
678+ GitFlow . VersionTagPrefix = versionTagPrefix ;
679+ }
680+ else if ( _branches != null && _branches . Count > 0 )
681+ {
682+ // Auto-detect GitFlow based on branch structure when no explicit config exists
683+ // Check for master or main branch
684+ var masterBranch = _branches . Find ( b => b . IsLocal && b . Name == "master" ) ;
685+ var mainBranch = _branches . Find ( b => b . IsLocal && b . Name == "main" ) ;
686+
687+ if ( masterBranch != null || mainBranch != null )
688+ {
689+ // Set master/main branch
690+ GitFlow . Master = masterBranch != null ? "master" : "main" ;
691+
692+ // Check for develop branch
693+ var developBranch = _branches . Find ( b => b . IsLocal && b . Name == "develop" ) ;
694+
695+ if ( developBranch != null )
696+ {
697+ GitFlow . Develop = "develop" ;
698+
699+ // Auto-detect common GitFlow prefixes based on existing branches
700+ bool hasFeatureBranches = _branches . Any ( b => b . IsLocal && b . Name . StartsWith ( "feature/" ) ) ;
701+ bool hasReleaseBranches = _branches . Any ( b => b . IsLocal && b . Name . StartsWith ( "release/" ) ) ;
702+ bool hasHotfixBranches = _branches . Any ( b => b . IsLocal && b . Name . StartsWith ( "hotfix/" ) ) ;
703+ bool hasSupportBranches = _branches . Any ( b => b . IsLocal && b . Name . StartsWith ( "support/" ) ) ;
704+
705+ // Set default GitFlow prefixes
706+ GitFlow . FeaturePrefix = "feature/" ;
707+ GitFlow . ReleasePrefix = "release/" ;
708+ GitFlow . HotfixPrefix = "hotfix/" ;
709+
710+ if ( hasSupportBranches )
711+ GitFlow . SupportPrefix = "support/" ;
712+
713+ GitFlow . VersionTagPrefix = "" ;
714+
715+ // Auto-initialize GitFlow configuration for the repository
716+ // This allows GitFlow commands to work without manual initialization
717+ Task . Run ( async ( ) =>
718+ {
719+ try
720+ {
721+ // Write GitFlow configuration synchronously to ensure it's set
722+ var configCmd = new Commands . Config ( _fullpath ) ;
723+ await configCmd . SetAsync ( "gitflow.branch.master" , GitFlow . Master ) . ConfigureAwait ( false ) ;
724+ await configCmd . SetAsync ( "gitflow.branch.develop" , GitFlow . Develop ) . ConfigureAwait ( false ) ;
725+ await configCmd . SetAsync ( "gitflow.prefix.feature" , GitFlow . FeaturePrefix ) . ConfigureAwait ( false ) ;
726+ await configCmd . SetAsync ( "gitflow.prefix.release" , GitFlow . ReleasePrefix ) . ConfigureAwait ( false ) ;
727+ await configCmd . SetAsync ( "gitflow.prefix.hotfix" , GitFlow . HotfixPrefix ) . ConfigureAwait ( false ) ;
728+ await configCmd . SetAsync ( "gitflow.prefix.bugfix" , "bugfix/" ) . ConfigureAwait ( false ) ;
729+ await configCmd . SetAsync ( "gitflow.prefix.support" , GitFlow . SupportPrefix ) . ConfigureAwait ( false ) ;
730+ await configCmd . SetAsync ( "gitflow.prefix.versiontag" , GitFlow . VersionTagPrefix ?? "" , true ) . ConfigureAwait ( false ) ;
731+ }
732+ catch ( Exception ex )
733+ {
734+ // Silently fail - auto-configuration is optional
735+ App . LogException ( ex ) ;
736+ }
737+ } ) ;
738+ }
739+ }
740+ }
614741 }
615742
616743 #endregion
744+
745+ /// <summary>
746+ /// Checks for GitFlow structure and auto-configures if detected
747+ /// </summary>
748+ private void CheckAndAutoConfigureGitFlow ( List < Models . Branch > localBranches )
749+ {
750+ // Check if GitFlow is already configured
751+ Task . Run ( async ( ) =>
752+ {
753+ var config = await new Commands . Config ( _fullpath ) . ReadAllAsync ( ) . ConfigureAwait ( false ) ;
754+ bool hasGitFlowConfig = config . Keys . Any ( k => k . StartsWith ( "gitflow." ) ) ;
755+
756+ if ( ! hasGitFlowConfig && localBranches != null && localBranches . Count > 0 )
757+ {
758+ // Check for master or main branch
759+ var masterBranch = localBranches . Find ( b => b . Name == "master" ) ;
760+ var mainBranch = localBranches . Find ( b => b . Name == "main" ) ;
761+ var developBranch = localBranches . Find ( b => b . Name == "develop" ) ;
762+
763+ if ( ( masterBranch != null || mainBranch != null ) && developBranch != null )
764+ {
765+ var primaryBranch = masterBranch != null ? "master" : "main" ;
766+
767+ // Write GitFlow configuration
768+ var configCmd = new Commands . Config ( _fullpath ) ;
769+ await configCmd . SetAsync ( "gitflow.branch.master" , primaryBranch ) . ConfigureAwait ( false ) ;
770+ await configCmd . SetAsync ( "gitflow.branch.develop" , "develop" ) . ConfigureAwait ( false ) ;
771+ await configCmd . SetAsync ( "gitflow.prefix.feature" , "feature/" ) . ConfigureAwait ( false ) ;
772+ await configCmd . SetAsync ( "gitflow.prefix.release" , "release/" ) . ConfigureAwait ( false ) ;
773+ await configCmd . SetAsync ( "gitflow.prefix.hotfix" , "hotfix/" ) . ConfigureAwait ( false ) ;
774+ await configCmd . SetAsync ( "gitflow.prefix.bugfix" , "bugfix/" ) . ConfigureAwait ( false ) ;
775+ await configCmd . SetAsync ( "gitflow.prefix.support" , "support/" ) . ConfigureAwait ( false ) ;
776+ await configCmd . SetAsync ( "gitflow.prefix.versiontag" , "" , true ) . ConfigureAwait ( false ) ;
777+
778+ // Update the GitFlow object
779+ ExecuteOnUIThread ( ( ) =>
780+ {
781+ GitFlow . Master = primaryBranch ;
782+ GitFlow . Develop = "develop" ;
783+ GitFlow . FeaturePrefix = "feature/" ;
784+ GitFlow . ReleasePrefix = "release/" ;
785+ GitFlow . HotfixPrefix = "hotfix/" ;
786+ GitFlow . SupportPrefix = "support/" ;
787+ GitFlow . VersionTagPrefix = "" ;
788+ } ) ;
789+
790+ System . Diagnostics . Debug . WriteLine ( $ "[GitFlow] Auto-configured for { primaryBranch } /develop structure") ;
791+ }
792+ }
793+ } ) ;
794+ }
617795 }
618796}
0 commit comments