@@ -873,7 +873,9 @@ static int parse_branchname_arg(int argc, const char **argv,
873
873
int argcount = 0 ;
874
874
unsigned char branch_rev [20 ];
875
875
const char * arg ;
876
- int has_dash_dash ;
876
+ int dash_dash_pos ;
877
+ int has_dash_dash = 0 ;
878
+ int i ;
877
879
878
880
/*
879
881
* case 1: git checkout <ref> -- [<paths>]
@@ -885,20 +887,30 @@ static int parse_branchname_arg(int argc, const char **argv,
885
887
*
886
888
* everything after the '--' must be paths.
887
889
*
888
- * case 3: git checkout <something> [<paths> ]
890
+ * case 3: git checkout <something> [-- ]
889
891
*
890
- * With no paths, if <something> is a commit, that is to
891
- * switch to the branch or detach HEAD at it. As a special case,
892
- * if <something> is A...B (missing A or B means HEAD but you can
893
- * omit at most one side), and if there is a unique merge base
894
- * between A and B, A...B names that merge base.
892
+ * (a) If <something> is a commit, that is to
893
+ * switch to the branch or detach HEAD at it. As a special case,
894
+ * if <something> is A...B (missing A or B means HEAD but you can
895
+ * omit at most one side), and if there is a unique merge base
896
+ * between A and B, A...B names that merge base.
895
897
*
896
- * With no paths, if <something> is _not_ a commit, no -t nor -b
897
- * was given, and there is a tracking branch whose name is
898
- * <something> in one and only one remote, then this is a short-hand
899
- * to fork local <something> from that remote-tracking branch.
898
+ * (b) If <something> is _not_ a commit, either "--" is present
899
+ * or <something> is not a path, no -t nor -b was given, and
900
+ * and there is a tracking branch whose name is <something>
901
+ * in one and only one remote, then this is a short-hand to
902
+ * fork local <something> from that remote-tracking branch.
900
903
*
901
- * Otherwise <something> shall not be ambiguous.
904
+ * (c) Otherwise, if "--" is present, treat it like case (1).
905
+ *
906
+ * (d) Otherwise :
907
+ * - if it's a reference, treat it like case (1)
908
+ * - else if it's a path, treat it like case (2)
909
+ * - else: fail.
910
+ *
911
+ * case 4: git checkout <something> <paths>
912
+ *
913
+ * The first argument must not be ambiguous.
902
914
* - If it's *only* a reference, treat it like case (1).
903
915
* - If it's only a path, treat it like case (2).
904
916
* - else: fail.
@@ -907,28 +919,59 @@ static int parse_branchname_arg(int argc, const char **argv,
907
919
if (!argc )
908
920
return 0 ;
909
921
910
- if (!strcmp (argv [0 ], "--" )) /* case (2) */
911
- return 1 ;
912
-
913
922
arg = argv [0 ];
914
- has_dash_dash = (argc > 1 ) && !strcmp (argv [1 ], "--" );
923
+ dash_dash_pos = -1 ;
924
+ for (i = 0 ; i < argc ; i ++ ) {
925
+ if (!strcmp (argv [i ], "--" )) {
926
+ dash_dash_pos = i ;
927
+ break ;
928
+ }
929
+ }
930
+ if (dash_dash_pos == 0 )
931
+ return 1 ; /* case (2) */
932
+ else if (dash_dash_pos == 1 )
933
+ has_dash_dash = 1 ; /* case (3) or (1) */
934
+ else if (dash_dash_pos >= 2 )
935
+ die (_ ("only one reference expected, %d given." ), dash_dash_pos );
915
936
916
937
if (!strcmp (arg , "-" ))
917
938
arg = "@{-1}" ;
918
939
919
940
if (get_sha1_mb (arg , rev )) {
920
- if (has_dash_dash ) /* case (1) */
921
- die (_ ("invalid reference: %s" ), arg );
922
- if (dwim_new_local_branch_ok &&
923
- !check_filename (NULL , arg ) &&
924
- argc == 1 ) {
941
+ /*
942
+ * Either case (3) or (4), with <something> not being
943
+ * a commit, or an attempt to use case (1) with an
944
+ * invalid ref.
945
+ *
946
+ * It's likely an error, but we need to find out if
947
+ * we should auto-create the branch, case (3).(b).
948
+ */
949
+ int recover_with_dwim = dwim_new_local_branch_ok ;
950
+
951
+ if (check_filename (NULL , arg ) && !has_dash_dash )
952
+ recover_with_dwim = 0 ;
953
+ /*
954
+ * Accept "git checkout foo" and "git checkout foo --"
955
+ * as candidates for dwim.
956
+ */
957
+ if (!(argc == 1 && !has_dash_dash ) &&
958
+ !(argc == 2 && has_dash_dash ))
959
+ recover_with_dwim = 0 ;
960
+
961
+ if (recover_with_dwim ) {
925
962
const char * remote = unique_tracking_name (arg , rev );
926
- if (!remote )
927
- return argcount ;
928
- * new_branch = arg ;
929
- arg = remote ;
930
- /* DWIMmed to create local branch */
931
- } else {
963
+ if (remote ) {
964
+ * new_branch = arg ;
965
+ arg = remote ;
966
+ /* DWIMmed to create local branch, case (3).(b) */
967
+ } else {
968
+ recover_with_dwim = 0 ;
969
+ }
970
+ }
971
+
972
+ if (!recover_with_dwim ) {
973
+ if (has_dash_dash )
974
+ die (_ ("invalid reference: %s" ), arg );
932
975
return argcount ;
933
976
}
934
977
}
@@ -958,7 +1001,7 @@ static int parse_branchname_arg(int argc, const char **argv,
958
1001
959
1002
if (!* source_tree ) /* case (1): want a tree */
960
1003
die (_ ("reference is not a tree: %s" ), arg );
961
- if (!has_dash_dash ) {/* case (3 -> 1) */
1004
+ if (!has_dash_dash ) {/* case (3).(d) -> ( 1) */
962
1005
/*
963
1006
* Do not complain the most common case
964
1007
* git checkout branch
0 commit comments