@@ -880,7 +880,9 @@ static int parse_branchname_arg(int argc, const char **argv,
880
880
int argcount = 0 ;
881
881
unsigned char branch_rev [20 ];
882
882
const char * arg ;
883
- int has_dash_dash ;
883
+ int dash_dash_pos ;
884
+ int has_dash_dash = 0 ;
885
+ int i ;
884
886
885
887
/*
886
888
* case 1: git checkout <ref> -- [<paths>]
@@ -892,20 +894,30 @@ static int parse_branchname_arg(int argc, const char **argv,
892
894
*
893
895
* everything after the '--' must be paths.
894
896
*
895
- * case 3: git checkout <something> [<paths> ]
897
+ * case 3: git checkout <something> [-- ]
896
898
*
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.
902
904
*
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.
907
910
*
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.
909
921
* - If it's *only* a reference, treat it like case (1).
910
922
* - If it's only a path, treat it like case (2).
911
923
* - else: fail.
@@ -914,28 +926,59 @@ static int parse_branchname_arg(int argc, const char **argv,
914
926
if (!argc )
915
927
return 0 ;
916
928
917
- if (!strcmp (argv [0 ], "--" )) /* case (2) */
918
- return 1 ;
919
-
920
929
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 );
922
943
923
944
if (!strcmp (arg , "-" ))
924
945
arg = "@{-1}" ;
925
946
926
947
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 ) {
932
969
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 );
939
982
return argcount ;
940
983
}
941
984
}
@@ -965,7 +1008,7 @@ static int parse_branchname_arg(int argc, const char **argv,
965
1008
966
1009
if (!* source_tree ) /* case (1): want a tree */
967
1010
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) */
969
1012
/*
970
1013
* Do not complain the most common case
971
1014
* git checkout branch
0 commit comments