@@ -27,7 +27,7 @@ use indicatif::{ProgressBar, ProgressStyle};
2727use std:: time:: Duration ;
2828use unicode_width:: UnicodeWidthStr ;
2929
30- use crate :: constants:: section_header;
30+ use crate :: constants:: { section_header, GIT_REMOTE_PREFIX , WORKTREES_SUBDIR } ;
3131use crate :: git:: { GitWorktreeManager , WorktreeInfo } ;
3232use crate :: hooks:: { self , HookContext } ;
3333use crate :: input_esc_raw:: {
@@ -524,7 +524,7 @@ fn create_worktree_internal(manager: &GitWorktreeManager) -> Result<bool> {
524524
525525 let options = vec ! [
526526 format!( "Same level as repository (../{name})" ) ,
527- format!( "In subdirectory ({repo_name}/worktrees /{name})" ) ,
527+ format!( "In subdirectory ({repo_name}/{} /{name})" , WORKTREES_SUBDIR ) ,
528528 ] ;
529529
530530 let selection = match Select :: with_theme ( & get_theme ( ) )
@@ -538,16 +538,16 @@ fn create_worktree_internal(manager: &GitWorktreeManager) -> Result<bool> {
538538 } ;
539539
540540 match selection {
541- 0 => format ! ( "../{}" , name) , // Same level
542- _ => format ! ( "worktrees /{}" , name) , // Subdirectory pattern
541+ 0 => format ! ( "../{}" , name) , // Same level
542+ _ => format ! ( "{} /{}" , WORKTREES_SUBDIR , name) , // Subdirectory pattern
543543 }
544544 } else {
545545 name. clone ( )
546546 } ;
547547
548548 // Branch handling
549549 println ! ( ) ;
550- let branch_options = vec ! [ "Create from current HEAD" , "Create from existing branch " ] ;
550+ let branch_options = vec ! [ "Create from current HEAD" , "Select branch (smart mode) " ] ;
551551
552552 let branch_choice = match Select :: with_theme ( & get_theme ( ) )
553553 . with_prompt ( "Select branch option" )
@@ -558,32 +558,221 @@ fn create_worktree_internal(manager: &GitWorktreeManager) -> Result<bool> {
558558 None => return Ok ( false ) ,
559559 } ;
560560
561- let branch = if branch_choice == 1 {
562- // Show existing branches
563- let branches = manager. list_branches ( ) ?;
564- if branches. is_empty ( ) {
565- utils:: print_warning ( "No branches found, creating from HEAD" ) ;
566- None
567- } else {
568- println ! ( ) ;
569- match Select :: with_theme ( & get_theme ( ) )
570- . with_prompt ( "Select a branch" )
571- . items ( & branches)
572- . interact_opt ( ) ?
573- {
574- Some ( selection) => Some ( branches[ selection] . clone ( ) ) ,
575- None => return Ok ( false ) ,
561+ let ( branch, new_branch_name) = match branch_choice {
562+ 1 => {
563+ // Select branch (smart mode)
564+ let ( local_branches, remote_branches) = manager. list_all_branches ( ) ?;
565+ if local_branches. is_empty ( ) && remote_branches. is_empty ( ) {
566+ utils:: print_warning ( "No branches found, creating from HEAD" ) ;
567+ ( None , None )
568+ } else {
569+ // Get branch to worktree mapping
570+ let branch_worktree_map = manager. get_branch_worktree_map ( ) ?;
571+
572+ // Create display items without section headers
573+ let mut branch_items: Vec < String > = Vec :: new ( ) ;
574+ let mut branch_refs: Vec < ( String , bool ) > = Vec :: new ( ) ; // (branch_name, is_remote)
575+
576+ // Add local branches
577+ for branch in & local_branches {
578+ if let Some ( worktree) = branch_worktree_map. get ( branch) {
579+ branch_items. push ( format ! (
580+ " {} {}" ,
581+ branch. white( ) ,
582+ format!( "(in use by '{}')" , worktree) . bright_red( )
583+ ) ) ;
584+ } else {
585+ branch_items. push ( format ! ( " {}" , branch. white( ) ) ) ;
586+ }
587+ branch_refs. push ( ( branch. clone ( ) , false ) ) ;
588+ }
589+
590+ // Add remote branches with clear distinction
591+ for branch in & remote_branches {
592+ let full_remote_name = format ! ( "{}{}" , GIT_REMOTE_PREFIX , branch) ;
593+ if let Some ( worktree) = branch_worktree_map. get ( & full_remote_name) {
594+ branch_items. push ( format ! (
595+ "↑ {} {}" ,
596+ full_remote_name. bright_blue( ) ,
597+ format!( "(in use by '{}')" , worktree) . bright_red( )
598+ ) ) ;
599+ } else {
600+ branch_items. push ( format ! ( "↑ {}" , full_remote_name. bright_blue( ) ) ) ;
601+ }
602+ branch_refs. push ( ( branch. clone ( ) , true ) ) ;
603+ }
604+
605+ println ! ( ) ;
606+ match Select :: with_theme ( & get_theme ( ) )
607+ . with_prompt ( "Select a branch" )
608+ . items ( & branch_items)
609+ . interact_opt ( ) ?
610+ {
611+ Some ( selection) => {
612+ let ( selected_branch, is_remote) = & branch_refs[ selection] ;
613+
614+ if !is_remote {
615+ // Local branch - check if already checked out
616+ if let Some ( worktree) = branch_worktree_map. get ( selected_branch) {
617+ // Branch is in use, offer to create a new branch
618+ println ! ( ) ;
619+ utils:: print_warning ( & format ! (
620+ "Branch '{}' is already checked out in worktree '{}'" ,
621+ selected_branch. yellow( ) ,
622+ worktree. bright_red( )
623+ ) ) ;
624+ println ! ( ) ;
625+
626+ let action_options = vec ! [
627+ format!(
628+ "Create new branch '{}' from '{}'" ,
629+ name, selected_branch
630+ ) ,
631+ "Change the branch name" . to_string( ) ,
632+ "Cancel" . to_string( ) ,
633+ ] ;
634+
635+ match Select :: with_theme ( & get_theme ( ) )
636+ . with_prompt ( "What would you like to do?" )
637+ . items ( & action_options)
638+ . interact_opt ( ) ?
639+ {
640+ Some ( 0 ) => {
641+ // Use worktree name as new branch name
642+ ( Some ( selected_branch. clone ( ) ) , Some ( name. clone ( ) ) )
643+ }
644+ Some ( 1 ) => {
645+ // Ask for custom branch name
646+ println ! ( ) ;
647+ let new_branch = match input_esc_with_default (
648+ & format ! (
649+ "Enter new branch name (base: {})" ,
650+ selected_branch. yellow( )
651+ ) ,
652+ & name,
653+ ) {
654+ Some ( name) => name. trim ( ) . to_string ( ) ,
655+ None => return Ok ( false ) ,
656+ } ;
657+
658+ if new_branch. is_empty ( ) {
659+ utils:: print_error ( "Branch name cannot be empty" ) ;
660+ return Ok ( false ) ;
661+ }
662+
663+ if local_branches. contains ( & new_branch) {
664+ utils:: print_error ( & format ! (
665+ "Branch '{}' already exists" ,
666+ new_branch
667+ ) ) ;
668+ return Ok ( false ) ;
669+ }
670+
671+ ( Some ( selected_branch. clone ( ) ) , Some ( new_branch) )
672+ }
673+ _ => return Ok ( false ) ,
674+ }
675+ } else {
676+ ( Some ( selected_branch. clone ( ) ) , None )
677+ }
678+ } else {
679+ // Remote branch - check if local branch with same name exists
680+ if local_branches. contains ( selected_branch) {
681+ // Local branch with same name exists
682+ println ! ( ) ;
683+ utils:: print_warning ( & format ! (
684+ "A local branch '{}' already exists for remote '{}'" ,
685+ selected_branch. yellow( ) ,
686+ format!( "{}{}" , GIT_REMOTE_PREFIX , selected_branch)
687+ . bright_blue( )
688+ ) ) ;
689+ println ! ( ) ;
690+
691+ let use_local_option = if let Some ( worktree) =
692+ branch_worktree_map. get ( selected_branch)
693+ {
694+ format ! (
695+ "Use the existing local branch instead (in use by '{}')" ,
696+ worktree. bright_red( )
697+ )
698+ } else {
699+ "Use the existing local branch instead" . to_string ( )
700+ } ;
701+
702+ let action_options = vec ! [
703+ format!(
704+ "Create new branch '{}' from '{}{}'" ,
705+ name, GIT_REMOTE_PREFIX , selected_branch
706+ ) ,
707+ use_local_option,
708+ "Cancel" . to_string( ) ,
709+ ] ;
710+
711+ match Select :: with_theme ( & get_theme ( ) )
712+ . with_prompt ( "What would you like to do?" )
713+ . items ( & action_options)
714+ . interact_opt ( ) ?
715+ {
716+ Some ( 0 ) => {
717+ // Create new branch with worktree name
718+ (
719+ Some ( format ! (
720+ "{}{}" ,
721+ GIT_REMOTE_PREFIX , selected_branch
722+ ) ) ,
723+ Some ( name. clone ( ) ) ,
724+ )
725+ }
726+ Some ( 1 ) => {
727+ // Use local branch instead - but check if it's already in use
728+ if let Some ( worktree) =
729+ branch_worktree_map. get ( selected_branch)
730+ {
731+ println ! ( ) ;
732+ utils:: print_error ( & format ! (
733+ "Branch '{}' is already checked out in worktree '{}'" ,
734+ selected_branch. yellow( ) ,
735+ worktree. bright_red( )
736+ ) ) ;
737+ println ! ( "Please select a different option." ) ;
738+ return Ok ( false ) ;
739+ }
740+ ( Some ( selected_branch. clone ( ) ) , None )
741+ }
742+ _ => return Ok ( false ) ,
743+ }
744+ } else {
745+ // No conflict, proceed normally
746+ (
747+ Some ( format ! ( "{}{}" , GIT_REMOTE_PREFIX , selected_branch) ) ,
748+ None ,
749+ )
750+ }
751+ }
752+ }
753+ None => return Ok ( false ) ,
754+ }
576755 }
577756 }
578- } else {
579- None
757+ _ => {
758+ // Create from current HEAD
759+ ( None , None )
760+ }
580761 } ;
581762
582763 // Show preview
583764 println ! ( ) ;
584765 println ! ( "{}" , "Preview:" . bright_white( ) ) ;
585766 println ! ( " {} {}" , "Name:" . bright_black( ) , final_name. bright_green( ) ) ;
586- if let Some ( branch_name) = & branch {
767+ if let Some ( new_branch) = & new_branch_name {
768+ let base_branch_name = branch. as_ref ( ) . unwrap ( ) ;
769+ println ! (
770+ " {} {} (from {})" ,
771+ "New Branch:" . bright_black( ) ,
772+ new_branch. yellow( ) ,
773+ base_branch_name. bright_black( )
774+ ) ;
775+ } else if let Some ( branch_name) = & branch {
587776 println ! ( " {} {}" , "Branch:" . bright_black( ) , branch_name. yellow( ) ) ;
588777 } else {
589778 println ! ( " {} Current HEAD" , "From:" . bright_black( ) ) ;
@@ -600,7 +789,15 @@ fn create_worktree_internal(manager: &GitWorktreeManager) -> Result<bool> {
600789 pb. set_message ( "Creating worktree..." ) ;
601790 pb. enable_steady_tick ( Duration :: from_millis ( 100 ) ) ;
602791
603- match manager. create_worktree ( & final_name, branch. as_deref ( ) ) {
792+ let result = if let Some ( new_branch) = & new_branch_name {
793+ // Create worktree with new branch from base branch
794+ manager. create_worktree_with_new_branch ( & final_name, new_branch, branch. as_ref ( ) . unwrap ( ) )
795+ } else {
796+ // Create worktree with existing branch or from HEAD
797+ manager. create_worktree ( & final_name, branch. as_deref ( ) )
798+ } ;
799+
800+ match result {
604801 Ok ( path) => {
605802 pb. finish_and_clear ( ) ;
606803 utils:: print_success ( & format ! (
0 commit comments