@@ -880,7 +880,9 @@ static int parse_branchname_arg(int argc, const char **argv,
880880 int argcount = 0 ;
881881 unsigned char branch_rev [20 ];
882882 const char * arg ;
883- int has_dash_dash ;
883+ int dash_dash_pos ;
884+ int has_dash_dash = 0 ;
885+ int i ;
884886
885887 /*
886888 * case 1: git checkout <ref> -- [<paths>]
@@ -892,20 +894,30 @@ static int parse_branchname_arg(int argc, const char **argv,
892894 *
893895 * everything after the '--' must be paths.
894896 *
895- * case 3: git checkout <something> [<paths> ]
897+ * case 3: git checkout <something> [-- ]
896898 *
897- * With no paths, if <something> is a commit, that is to
898- * switch to the branch or detach HEAD at it. As a special case,
899- * if <something> is A...B (missing A or B means HEAD but you can
900- * omit at most one side), and if there is a unique merge base
901- * between A and B, A...B names that merge base.
899+ * (a) If <something> is a commit, that is to
900+ * switch to the branch or detach HEAD at it. As a special case,
901+ * if <something> is A...B (missing A or B means HEAD but you can
902+ * omit at most one side), and if there is a unique merge base
903+ * between A and B, A...B names that merge base.
902904 *
903- * With no paths, if <something> is _not_ a commit, no -t nor -b
904- * was given, and there is a tracking branch whose name is
905- * <something> in one and only one remote, then this is a short-hand
906- * to fork local <something> from that remote-tracking branch.
905+ * (b) If <something> is _not_ a commit, either "--" is present
906+ * or <something> is not a path, no -t nor -b was given, and
907+ * and there is a tracking branch whose name is <something>
908+ * in one and only one remote, then this is a short-hand to
909+ * fork local <something> from that remote-tracking branch.
907910 *
908- * Otherwise <something> shall not be ambiguous.
911+ * (c) Otherwise, if "--" is present, treat it like case (1).
912+ *
913+ * (d) Otherwise :
914+ * - if it's a reference, treat it like case (1)
915+ * - else if it's a path, treat it like case (2)
916+ * - else: fail.
917+ *
918+ * case 4: git checkout <something> <paths>
919+ *
920+ * The first argument must not be ambiguous.
909921 * - If it's *only* a reference, treat it like case (1).
910922 * - If it's only a path, treat it like case (2).
911923 * - else: fail.
@@ -914,28 +926,59 @@ static int parse_branchname_arg(int argc, const char **argv,
914926 if (!argc )
915927 return 0 ;
916928
917- if (!strcmp (argv [0 ], "--" )) /* case (2) */
918- return 1 ;
919-
920929 arg = argv [0 ];
921- has_dash_dash = (argc > 1 ) && !strcmp (argv [1 ], "--" );
930+ dash_dash_pos = -1 ;
931+ for (i = 0 ; i < argc ; i ++ ) {
932+ if (!strcmp (argv [i ], "--" )) {
933+ dash_dash_pos = i ;
934+ break ;
935+ }
936+ }
937+ if (dash_dash_pos == 0 )
938+ return 1 ; /* case (2) */
939+ else if (dash_dash_pos == 1 )
940+ has_dash_dash = 1 ; /* case (3) or (1) */
941+ else if (dash_dash_pos >= 2 )
942+ die (_ ("only one reference expected, %d given." ), dash_dash_pos );
922943
923944 if (!strcmp (arg , "-" ))
924945 arg = "@{-1}" ;
925946
926947 if (get_sha1_mb (arg , rev )) {
927- if (has_dash_dash ) /* case (1) */
928- die (_ ("invalid reference: %s" ), arg );
929- if (dwim_new_local_branch_ok &&
930- !check_filename (NULL , arg ) &&
931- argc == 1 ) {
948+ /*
949+ * Either case (3) or (4), with <something> not being
950+ * a commit, or an attempt to use case (1) with an
951+ * invalid ref.
952+ *
953+ * It's likely an error, but we need to find out if
954+ * we should auto-create the branch, case (3).(b).
955+ */
956+ int recover_with_dwim = dwim_new_local_branch_ok ;
957+
958+ if (check_filename (NULL , arg ) && !has_dash_dash )
959+ recover_with_dwim = 0 ;
960+ /*
961+ * Accept "git checkout foo" and "git checkout foo --"
962+ * as candidates for dwim.
963+ */
964+ if (!(argc == 1 && !has_dash_dash ) &&
965+ !(argc == 2 && has_dash_dash ))
966+ recover_with_dwim = 0 ;
967+
968+ if (recover_with_dwim ) {
932969 const char * remote = unique_tracking_name (arg , rev );
933- if (!remote )
934- return argcount ;
935- * new_branch = arg ;
936- arg = remote ;
937- /* DWIMmed to create local branch */
938- } else {
970+ if (remote ) {
971+ * new_branch = arg ;
972+ arg = remote ;
973+ /* DWIMmed to create local branch, case (3).(b) */
974+ } else {
975+ recover_with_dwim = 0 ;
976+ }
977+ }
978+
979+ if (!recover_with_dwim ) {
980+ if (has_dash_dash )
981+ die (_ ("invalid reference: %s" ), arg );
939982 return argcount ;
940983 }
941984 }
@@ -965,7 +1008,7 @@ static int parse_branchname_arg(int argc, const char **argv,
9651008
9661009 if (!* source_tree ) /* case (1): want a tree */
9671010 die (_ ("reference is not a tree: %s" ), arg );
968- if (!has_dash_dash ) {/* case (3 -> 1) */
1011+ if (!has_dash_dash ) {/* case (3).(d) -> ( 1) */
9691012 /*
9701013 * Do not complain the most common case
9711014 * git checkout branch
0 commit comments