@@ -572,6 +572,40 @@ static int interactive_checkout(const char *revision, const char **pathspec,
572572 return run_add_interactive (revision , "--patch=checkout" , pathspec );
573573}
574574
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+ }
575609
576610int cmd_checkout (int argc , const char * * argv , const char * prefix )
577611{
@@ -582,6 +616,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
582616 struct tree * source_tree = NULL ;
583617 char * conflict_style = NULL ;
584618 int patch_mode = 0 ;
619+ int dwim_new_local_branch = 1 ;
585620 struct option options [] = {
586621 OPT__QUIET (& opts .quiet ),
587622 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)
597632 OPT_STRING (0 , "conflict" , & conflict_style , "style" ,
598633 "conflict style (merge or diff3)" ),
599634 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 },
600638 OPT_END (),
601639 };
602640 int has_dash_dash ;
@@ -630,8 +668,6 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
630668 opts .new_branch = argv0 + 1 ;
631669 }
632670
633- if (opts .track == BRANCH_TRACK_UNSPECIFIED )
634- opts .track = git_branch_track ;
635671 if (conflict_style ) {
636672 opts .merge = 1 ; /* implied */
637673 git_xmerge_config ("merge.conflictstyle" , conflict_style , NULL );
@@ -655,6 +691,11 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)
655691 * With no paths, if <something> is a commit, that is to
656692 * switch to the branch or detach HEAD at it.
657693 *
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+ *
658699 * Otherwise <something> shall not be ambiguous.
659700 * - If it's *only* a reference, treat it like case (1).
660701 * - 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)
677718 if (get_sha1 (arg , rev )) {
678719 if (has_dash_dash ) /* case (1) */
679720 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 ;
681736 }
682737
683738 /* 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)
715770 }
716771
717772no_reference :
773+
774+ if (opts .track == BRANCH_TRACK_UNSPECIFIED )
775+ opts .track = git_branch_track ;
776+
718777 if (argc ) {
719778 const char * * pathspec = get_pathspec (prefix , argv );
720779
0 commit comments