@@ -572,6 +572,40 @@ static int interactive_checkout(const char *revision, const char **pathspec,
572
572
return run_add_interactive (revision , "--patch=checkout" , pathspec );
573
573
}
574
574
575
+ struct tracking_name_data {
576
+ const char * name ;
577
+ char * remote ;
578
+ int unique ;
579
+ };
580
+
581
+ static int check_tracking_name (const char * refname , const unsigned char * sha1 ,
582
+ int flags , void * cb_data )
583
+ {
584
+ struct tracking_name_data * cb = cb_data ;
585
+ const char * slash ;
586
+
587
+ if (prefixcmp (refname , "refs/remotes/" ))
588
+ return 0 ;
589
+ slash = strchr (refname + 13 , '/' );
590
+ if (!slash || strcmp (slash + 1 , cb -> name ))
591
+ return 0 ;
592
+ if (cb -> remote ) {
593
+ cb -> unique = 0 ;
594
+ return 0 ;
595
+ }
596
+ cb -> remote = xstrdup (refname );
597
+ return 0 ;
598
+ }
599
+
600
+ static const char * unique_tracking_name (const char * name )
601
+ {
602
+ struct tracking_name_data cb_data = { name , NULL , 1 };
603
+ for_each_ref (check_tracking_name , & cb_data );
604
+ if (cb_data .unique )
605
+ return cb_data .remote ;
606
+ free (cb_data .remote );
607
+ return NULL ;
608
+ }
575
609
576
610
int cmd_checkout (int argc , const char * * argv , const char * prefix )
577
611
{
@@ -582,6 +616,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
582
616
struct tree * source_tree = NULL ;
583
617
char * conflict_style = NULL ;
584
618
int patch_mode = 0 ;
619
+ int dwim_new_local_branch = 1 ;
585
620
struct option options [] = {
586
621
OPT__QUIET (& opts .quiet ),
587
622
OPT_STRING ('b' , NULL , & opts .new_branch , "new branch" , "branch" ),
@@ -597,6 +632,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
597
632
OPT_STRING (0 , "conflict" , & conflict_style , "style" ,
598
633
"conflict style (merge or diff3)" ),
599
634
OPT_BOOLEAN ('p' , "patch" , & patch_mode , "select hunks interactively" ),
635
+ { OPTION_BOOLEAN , 0 , "guess" , & dwim_new_local_branch , NULL ,
636
+ "second guess 'git checkout no-such-branch'" ,
637
+ PARSE_OPT_NOARG | PARSE_OPT_HIDDEN },
600
638
OPT_END (),
601
639
};
602
640
int has_dash_dash ;
@@ -630,8 +668,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
630
668
opts .new_branch = argv0 + 1 ;
631
669
}
632
670
633
- if (opts .track == BRANCH_TRACK_UNSPECIFIED )
634
- opts .track = git_branch_track ;
635
671
if (conflict_style ) {
636
672
opts .merge = 1 ; /* implied */
637
673
git_xmerge_config ("merge.conflictstyle" , conflict_style , NULL );
@@ -655,6 +691,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
655
691
* With no paths, if <something> is a commit, that is to
656
692
* switch to the branch or detach HEAD at it.
657
693
*
694
+ * With no paths, if <something> is _not_ a commit, no -t nor -b
695
+ * was given, and there is a tracking branch whose name is
696
+ * <something> in one and only one remote, then this is a short-hand
697
+ * to fork local <something> from that remote tracking branch.
698
+ *
658
699
* Otherwise <something> shall not be ambiguous.
659
700
* - If it's *only* a reference, treat it like case (1).
660
701
* - If it's only a path, treat it like case (2).
@@ -677,7 +718,21 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
677
718
if (get_sha1 (arg , rev )) {
678
719
if (has_dash_dash ) /* case (1) */
679
720
die ("invalid reference: %s" , arg );
680
- goto no_reference ; /* case (3 -> 2) */
721
+ if (!patch_mode &&
722
+ dwim_new_local_branch &&
723
+ opts .track == BRANCH_TRACK_UNSPECIFIED &&
724
+ !opts .new_branch &&
725
+ !check_filename (NULL , arg ) &&
726
+ argc == 1 ) {
727
+ const char * remote = unique_tracking_name (arg );
728
+ if (!remote || get_sha1 (remote , rev ))
729
+ goto no_reference ;
730
+ opts .new_branch = arg ;
731
+ arg = remote ;
732
+ /* DWIMmed to create local branch */
733
+ }
734
+ else
735
+ goto no_reference ;
681
736
}
682
737
683
738
/* we can't end up being in (2) anymore, eat the argument */
@@ -715,6 +770,10 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
715
770
}
716
771
717
772
no_reference :
773
+
774
+ if (opts .track == BRANCH_TRACK_UNSPECIFIED )
775
+ opts .track = git_branch_track ;
776
+
718
777
if (argc ) {
719
778
const char * * pathspec = get_pathspec (prefix , argv );
720
779
0 commit comments