@@ -12,22 +12,13 @@ import (
1212 "git-genius/internal/ui"
1313)
1414
15- func ChangeProjectDir () bool {
16- return switchProject (false )
17- }
18-
19- func SwitchProjectRepo () bool {
20- return switchProject (true )
21- }
22-
23- func switchProject (withRepoOptions bool ) bool {
24- title := "Change Project Directory"
25- if withRepoOptions {
26- title = "Switch Project / Repo"
27- }
28-
15+ /*
16+ SwitchProject is the unified entry point for changing the active project directory.
17+ It detects if the target is a Git repo and shows context before switching.
18+ */
19+ func SwitchProject () bool {
2920 ui .Clear ()
30- ui .Header (title )
21+ ui .Header ("Switch Project" )
3122
3223 current := config .Load ().GetWorkDir ()
3324 ui .Info ("Current project directory:" )
@@ -52,33 +43,65 @@ func switchProject(withRepoOptions bool) bool {
5243 return false
5344 }
5445
55- cfg , isRepo , err := activateProjectDir (resolveRecentDir (dir , recent ))
46+ targetDir := resolveRecentDir (dir , recent )
47+ abs , err := filepath .Abs (targetDir )
5648 if err != nil {
57- ui .Error (err .Error ())
49+ ui .Error ("Failed to resolve directory path" )
50+ if ! ui .ConfirmDefault ("Try another directory?" , true ) {
51+ return false
52+ }
53+ continue
54+ }
55+
56+ info , err := os .Stat (abs )
57+ if err != nil || ! info .IsDir () {
58+ ui .Error ("Invalid directory path" )
5859 if ! ui .ConfirmDefault ("Try another directory?" , true ) {
5960 return false
6061 }
6162 continue
6263 }
6364
65+ // Load config for the target directory to show context
66+ targetCfg := config .LoadForWorkDir (abs )
67+ isRepo := system .IsGitRepoAt (abs )
68+
69+ ui .Divider ()
70+ ui .Info ("Target Directory: " + abs )
71+ if isRepo {
72+ ui .Success ("Git repository detected" )
73+ showRepoContext (abs , targetCfg )
74+ } else {
75+ ui .Warn ("Not a git repository" )
76+ }
77+ ui .Divider ()
78+
79+ if ! ui .ConfirmDefault ("Switch to this project?" , true ) {
80+ if ui .Confirm ("Try another directory?" ) {
81+ continue
82+ }
83+ return false
84+ }
85+
86+ // Perform the switch
87+ config .SetActiveWorkDir (abs )
6488 ui .Success ("Project directory updated" )
65- ui .Info ("New project directory:" )
66- ui .Info (cfg .WorkDir )
6789
6890 if ! isRepo {
69- return handleNonRepoSelection (cfg )
91+ return handleNonRepoSelection (targetCfg )
7092 }
7193
72- ui . Success ( "Git repository detected in new directory" )
73- bootstrapProjectConfig (& cfg )
94+ // Sync branch/remote defaults if it's a new repo for Git Genius
95+ bootstrapProjectConfig (& targetCfg )
7496
75- if ! system .EnsureBranchSync () {
76- return false
97+ // Offer post-switch options if Git is available
98+ if system .CommandExists ("git" ) {
99+ if ! system .EnsureBranchSync () {
100+ return false
101+ }
102+ return offerRepoSwitchOptions (targetCfg )
77103 }
78104
79- if withRepoOptions {
80- return offerRepoSwitchOptions (cfg )
81- }
82105 return true
83106 }
84107}
@@ -93,29 +116,32 @@ func resolveRecentDir(input string, recent []string) string {
93116 return input
94117}
95118
96- func activateProjectDir (dir string ) (config.Config , bool , error ) {
97- abs , err := filepath .Abs (strings .TrimSpace (dir ))
98- if err != nil {
99- return config.Config {}, false , fmt .Errorf ("failed to resolve directory path" )
119+ func showRepoContext (dir string , cfg config.Config ) {
120+ // We need to temporarily set the work dir to inspect it, or use GitOutputAt
121+ branch , _ := system .GitOutputAt (dir , "branch" , "--show-current" )
122+ if branch == "" {
123+ branch = cfg .Branch
100124 }
101-
102- info , err := os .Stat (abs )
103- if err != nil || ! info .IsDir () {
104- return config.Config {}, false , fmt .Errorf ("invalid directory path" )
125+ if branch == "" {
126+ branch = "-"
105127 }
106128
107- config .SetActiveWorkDir (abs )
108-
109- if system .IsGitRepo () {
110- system .EnsureSafeDirectory (abs )
111- cfg := config .Load ()
112- cfg .WorkDir = abs
113- return cfg , true , nil
129+ remote := cfg .Remote
130+ if remote == "" {
131+ // Try to auto-detect a remote if not in config
132+ if remotes , err := system .RemoteNames (); err == nil && len (remotes ) > 0 {
133+ remote = remotes [0 ]
134+ }
135+ }
136+ if remote == "" {
137+ remote = "-"
114138 }
115139
116- cfg := config .LoadForWorkDir (abs )
117- cfg .WorkDir = abs
118- return cfg , false , nil
140+ ui .Info ("Branch : " + branch )
141+ ui .Info ("Remote : " + remote )
142+ if cfg .Owner != "" && cfg .Repo != "" {
143+ ui .Info ("Repo : https://github.com/" + cfg .Owner + "/" + cfg .Repo )
144+ }
119145}
120146
121147func bootstrapProjectConfig (cfg * config.Config ) {
@@ -126,14 +152,17 @@ func bootstrapProjectConfig(cfg *config.Config) {
126152 changed := false
127153
128154 if ! config .HasProjectConfig (cfg .WorkDir ) {
129- if branch := system .CurrentGitBranch ( ); branch != "" {
155+ if branch , _ := system .GitOutputAt ( cfg . WorkDir , "branch" , "--show-current" ); branch != "" {
130156 cfg .Branch = branch
131157 changed = true
132158 }
133159
134- if remotes , err := system .RemoteNames (); err == nil && len (remotes ) == 1 {
135- cfg .Remote = remotes [0 ]
136- changed = true
160+ if remotes , err := system .GitOutputAt (cfg .WorkDir , "remote" ); err == nil && remotes != "" {
161+ lines := strings .Split (remotes , "\n " )
162+ if len (lines ) > 0 && lines [0 ] != "" {
163+ cfg .Remote = strings .TrimSpace (lines [0 ])
164+ changed = true
165+ }
137166 }
138167 }
139168
@@ -142,17 +171,21 @@ func bootstrapProjectConfig(cfg *config.Config) {
142171 }
143172
144173 config .Save (* cfg )
145- ui .Info ("Loaded repo defaults for this project so setup does not need to be repeated " )
174+ ui .Info ("Loaded repo defaults for this project" )
146175}
147176
148177func handleNonRepoSelection (cfg config.Config ) bool {
149- ui .Warn ("Selected directory is not a git repository" )
178+ if ! system .CommandExists ("git" ) {
179+ ui .Warn ("Git is not installed. Operations will be limited." )
180+ return true
181+ }
182+
150183 if ! ui .Confirm ("Initialize a git repository here?" ) {
151184 ui .Warn ("Git operations will be limited until repo is initialized" )
152185 return true
153186 }
154187
155- if err := system .RunGit ( "init" ); err != nil {
188+ if err := system .RunGitAt ( cfg . WorkDir , "init" ); err != nil {
156189 ui .Error ("Failed to initialize git repository" )
157190 return false
158191 }
@@ -161,37 +194,39 @@ func handleNonRepoSelection(cfg config.Config) bool {
161194 bootstrapProjectConfig (& cfg )
162195
163196 if cfg .Branch != "" {
164- if err := system .PrepareBranch (cfg .Branch ); err != nil {
165- ui .Warn ("Could not prepare configured branch" )
166- ui .Info (err .Error ())
167- } else {
168- ui .Success ("Branch ready: " + cfg .Branch )
169- }
197+ // We can't use PrepareBranch easily here because it uses config.Load()
198+ // but we just initialized a repo. Let's just try to create/checkout.
199+ _ = system .RunGitAt (cfg .WorkDir , "checkout" , "-b" , cfg .Branch )
170200 }
171201
172202 return true
173203}
174204
175205func offerRepoSwitchOptions (cfg config.Config ) bool {
176- ui .Info ("Saved branch : " + cfg .Branch )
177- ui .Info ("Saved remote : " + cfg .Remote )
206+ ui .Info ("Current branch : " + cfg .Branch )
207+ ui .Info ("Current remote : " + cfg .Remote )
178208
179- if ui .Confirm ("Switch branch in this repo now?" ) {
209+ if ui .Confirm ("Switch branch now?" ) {
180210 if ! gitops .SwitchBranch () {
181211 return false
182212 }
183213 }
184214
185- if ui .Confirm ("Configure or switch the active remote now?" ) {
215+ if ui .Confirm ("Configure or switch remote now?" ) {
186216 if ! gitops .SwitchRemote () {
187217 return false
188218 }
189219 }
190220
191- if ! config .HasProjectConfig (cfg .WorkDir ) {
192- ui .Info ("This repo is using auto-detected defaults right now" )
193- ui .Info ("Run Tools -> Setup / Reconfigure later if you want to save owner/repo details too" )
194- }
195-
196221 return true
197222}
223+
224+ // Deprecated: used for backward compatibility during refactor
225+ func ChangeProjectDir () bool {
226+ return SwitchProject ()
227+ }
228+
229+ // Deprecated: used for backward compatibility during refactor
230+ func SwitchProjectRepo () bool {
231+ return SwitchProject ()
232+ }
0 commit comments