{"thread":{"id":"48476","subject":"[PATCH 1/3] checkout.c: add strict usage of -- before file_path","startedAt":"2018-05-13T02:24:12Z","lastAt":"2018-05-14T15:43:27Z","messageCount":11,"participants":["Dannier Castro L","Duy Nguyen","SZEDER Gábor","Kevin Daudt","Philip Oakley","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"347480","messageId":"1526178214-30956-1-git-send-email-danniercl@gmail.com","threadId":"48476","inReplyTo":null,"subject":"[PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Dannier Castro L","fromEmail":"danniercl@gmail.com","sentAt":"2018-05-13T02:23:32Z","receivedAt":"2018-05-13T02:24:12Z","isPatch":true,"sender":{"key":"danniercl@gmail.com","avatar":null},"body":"Currently, <checkout> is a complex command able to handle both\nbranches and files without any distintion other than their names,\ntaking into account that depending on the type (branch or file),\nthe functionality is completely different, the easier example:\n\n$ git checkout <branch>  # Switch from current branch to <branch>.\n$ git checkout <file>    # Restore <file> from HEAD, discarding\n                         # changes if it's necessary.\n$ git checkout -- <file> # The same as the last one, only with an\n                         # useless '--'.\n\nFor GIT new users, this complicated versatility of <checkout> could\nbe very confused, also considering that actually the flag '--' is\ncompletely useless (added or not, there is not any difference for\nthis command), when the same program messages promote the use of\nthis flag.\n\nRegarding the <checkout>'s power to overwrite any file, discarding\nchanges if they exist without some way of recovering them, the\nsolution propuses that the usage of '--' is strict before to\nspecify the file(s) path(s) for any <checkout> command (including\nall types of flags), as a \"defense barrier\" to make sure about\nuser's knowledge and intension running <checkout>.\n\nThe solution consists in detect '--' into command args, allowing\nthe discard of changes and considering the following names as\nfile paths, otherwise, they are branch names.\n\nSigned-off-by: Dannier Castro L <danniercl@gmail.com>\n---\n builtin/checkout.c | 30 +++++++++++++++++-------------\n 1 file changed, 17 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex d76e13c..ec577b3 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -40,6 +40,7 @@ struct checkout_opts {\n \tint ignore_skipworktree;\n \tint ignore_other_worktrees;\n \tint show_progress;\n+\tint discard_changes;\n \n \tconst char *new_branch;\n \tconst char *new_branch_force;\n@@ -885,8 +886,8 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t/*\n \t * case 1: git checkout <ref> -- [<paths>]\n \t *\n-\t *   <ref> must be a valid tree, everything after the '--' must be\n-\t *   a path.\n+\t *   <ref> must be a valid tree. '--' must always be before any path,\n+\t *   it means, everything after the '--' must be a path.\n \t *\n \t * case 2: git checkout -- [<paths>]\n \t *\n@@ -900,26 +901,28 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t *       omit at most one side), and if there is a unique merge base\n \t *       between A and B, A...B names that merge base.\n \t *\n-\t *   (b) If <something> is _not_ a commit, either \"--\" is present\n-\t *       or <something> is not a path, no -t or -b was given, and\n-\t *       and there is a tracking branch whose name is <something>\n-\t *       in one and only one remote, then this is a short-hand to\n-\t *       fork local <something> from that remote-tracking branch.\n+\t *   (b) If <something> is _not_ a commit, either \"--\" is present,\n+\t *       no -t or -b was given, and there is a tracking branch\n+\t *       whose name is <something> in one and only one remote,\n+\t *       then this is a short-hand to fork local <something> from\n+\t *       that remote-tracking branch.\n \t *\n \t *   (c) Otherwise, if \"--\" is present, treat it like case (1).\n \t *\n \t *   (d) Otherwise :\n \t *       - if it's a reference, treat it like case (1)\n-\t *       - else if it's a path, treat it like case (2)\n \t *       - else: fail.\n \t *\n-\t * case 4: git checkout <something> <paths>\n+\t *   <something> can never be a path (at least without '--' before).\n+\t *\n+\t * case 4: git checkout <something> -- <paths>\n \t *\n \t *   The first argument must not be ambiguous.\n \t *   - If it's *only* a reference, treat it like case (1).\n-\t *   - If it's only a path, treat it like case (2).\n \t *   - else: fail.\n \t *\n+\t *   <something> can never be a path (at least without '--' before).\n+\t *\n \t */\n \tif (!argc)\n \t\treturn 0;\n@@ -928,6 +931,7 @@ static int parse_branchname_arg(int argc, const char **argv,\n \tdash_dash_pos = -1;\n \tfor (i = 0; i < argc; i++) {\n \t\tif (!strcmp(argv[i], \"--\")) {\n+\t\t\topts->discard_changes = 1;\n \t\t\tdash_dash_pos = i;\n \t\t\tbreak;\n \t\t}\n@@ -957,8 +961,8 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t\t    (check_filename(opts->prefix, arg) || !no_wildcard(arg)))\n \t\t\trecover_with_dwim = 0;\n \t\t/*\n-\t\t * Accept \"git checkout foo\" and \"git checkout foo --\"\n-\t\t * as candidates for dwim.\n+\t\t * Accept \"git checkout foo_branch\" and\n+\t\t * \"git checkout foo_branch --\" as candidates for dwim.\n \t\t */\n \t\tif (!(argc == 1 && !has_dash_dash) &&\n \t\t    !(argc == 2 && has_dash_dash))\n@@ -1254,7 +1258,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t}\n \n \tUNLEAK(opts);\n-\tif (opts.patch_mode || opts.pathspec.nr)\n+\tif (opts.patch_mode || (opts.pathspec.nr && opts.discard_changes))\n \t\treturn checkout_paths(&opts, new_branch_info.name);\n \telse\n \t\treturn checkout_branch(&opts, &new_branch_info);\n-- \n2.7.4\n\n"},{"id":"347481","messageId":"1526178214-30956-2-git-send-email-danniercl@gmail.com","threadId":"48476","inReplyTo":"1526178214-30956-1-git-send-email-danniercl@gmail.com","subject":"[PATCH 2/3] test: update tests for strict usage of -- checkout","fromName":"Dannier Castro L","fromEmail":"danniercl@gmail.com","sentAt":"2018-05-13T02:23:33Z","receivedAt":"2018-05-13T02:24:19Z","isPatch":true,"sender":{"key":"danniercl@gmail.com","avatar":null},"body":"The flag '--' must always be before any file path when <checkout>\ncommand is used.\n\nThe list of 34 test files updated is shown:\n\n  t0021-conversion.sh\n  t0027-auto-crlf.sh\n  t1011-read-tree-sparse-checkout.sh\n  t1050-large.sh\n  t1051-large-conversion.sh\n  t2009-checkout-statinfo.sh\n  t2010-checkout-ambiguous.sh\n  t2013-checkout-submodule.sh\n  t2016-checkout-patch.sh\n  t2022-checkout-paths.sh\n  t2028-worktree-move.sh\n  t2030-unresolve-info.sh\n  t3001-ls-files-others-exclude.sh\n  t3509-cherry-pick-merge-df.sh\n  t3510-cherry-pick-sequence.sh\n  t4015-diff-whitespace.sh\n  t4124-apply-ws-rule.sh\n  t5403-post-checkout-hook.sh\n  t6007-rev-list-cherry-pick-file.sh\n  t6026-merge-attr.sh\n  t6030-bisect-porcelain.sh\n  t6111-rev-list-treesame.sh\n  t7001-mv.sh\n  t7008-grep-binary.sh\n  t7201-co.sh\n  t7300-clean.sh\n  t7501-commit.sh\n  t7502-commit.sh\n  t7607-merge-overwrite.sh\n  t7810-grep.sh\n  t7811-grep-open.sh\n  t8006-blame-textconv.sh\n  t9010-svn-fe.sh\n  t8003-blame-corner-cases.sh\n\nSigned-off-by: Dannier Castro L <danniercl@gmail.com>\n---\n t/t0021-conversion.sh                | 12 ++++++------\n t/t0027-auto-crlf.sh                 |  4 ++--\n t/t1011-read-tree-sparse-checkout.sh |  4 ++--\n t/t1050-large.sh                     |  2 +-\n t/t1051-large-conversion.sh          |  4 ++--\n t/t2009-checkout-statinfo.sh         |  6 +++---\n t/t2010-checkout-ambiguous.sh        |  4 ++--\n t/t2013-checkout-submodule.sh        |  4 ++--\n t/t2016-checkout-patch.sh            |  9 +--------\n t/t2022-checkout-paths.sh            |  4 ++--\n t/t2028-worktree-move.sh             |  2 +-\n t/t2030-unresolve-info.sh            |  6 +++---\n t/t3001-ls-files-others-exclude.sh   |  2 +-\n t/t3420-rebase-autostash.sh          |  2 +-\n t/t3510-cherry-pick-sequence.sh      |  4 ++--\n t/t3910-mac-os-precompose.sh         |  4 ++--\n t/t4015-diff-whitespace.sh           |  4 ++--\n t/t4117-apply-reject.sh              |  2 +-\n t/t4124-apply-ws-rule.sh             | 16 ++++++++--------\n t/t5403-post-checkout-hook.sh        |  2 +-\n t/t6007-rev-list-cherry-pick-file.sh |  2 +-\n t/t6026-merge-attr.sh                |  2 +-\n t/t6030-bisect-porcelain.sh          |  2 +-\n t/t6038-merge-text-auto.sh           |  2 +-\n t/t6050-replace.sh                   |  2 +-\n t/t6111-rev-list-treesame.sh         |  2 +-\n t/t7001-mv.sh                        |  2 +-\n t/t7008-grep-binary.sh               |  2 +-\n t/t7201-co.sh                        |  8 ++++----\n t/t7300-clean.sh                     |  2 +-\n t/t7501-commit.sh                    | 10 +++++-----\n t/t7502-commit.sh                    |  2 +-\n t/t7607-merge-overwrite.sh           |  4 ++--\n t/t7810-grep.sh                      |  2 +-\n t/t7811-grep-open.sh                 |  2 +-\n t/t8003-blame-corner-cases.sh        |  2 +-\n t/t8006-blame-textconv.sh            |  2 +-\n t/t9010-svn-fe.sh                    |  2 +-\n 38 files changed, 71 insertions(+), 78 deletions(-)\n\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex 46f8e58..9f4955a 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -380,7 +380,7 @@ test_expect_success PERL 'required process filter should filter data' '\n \t\tgit commit -m \"test commit 2\" &&\n \t\trm -f test2.r \"testsubdir/test3 '\\''sq'\\'',\\$x=.r\" &&\n \n-\t\tfilter_git checkout --quiet --no-progress . &&\n+\t\tfilter_git checkout --quiet --no-progress -- . &&\n \t\tcat >expected.log <<-EOF &&\n \t\t\tSTART\n \t\t\tinit handshake complete\n@@ -466,7 +466,7 @@ test_expect_success PERL 'required process filter should be used only for \"clean\n \n \t\trm test.r &&\n \n-\t\tfilter_git checkout --quiet --no-progress . &&\n+\t\tfilter_git checkout --quiet --no-progress -- . &&\n \t\t# If the filter would be used for \"smudge\", too, we would see\n \t\t# \"IN: smudge test.r 57 [OK] -- OUT: 57 . [OK]\" here\n \t\tcat >expected.log <<-EOF &&\n@@ -580,7 +580,7 @@ test_expect_success PERL 'process filter should restart after unexpected write f\n \t\trm -f *.r &&\n \n \t\trm -f debug.log &&\n-\t\tgit checkout --quiet --no-progress . 2>git-stderr.log &&\n+\t\tgit checkout --quiet --no-progress -- . 2>git-stderr.log &&\n \n \t\tgrep \"smudge write error at\" git-stderr.log &&\n \t\tgrep \"error: external filter\" git-stderr.log &&\n@@ -630,7 +630,7 @@ test_expect_success PERL 'process filter should not be restarted if it signals a\n \t\tgit add . &&\n \t\trm -f *.r &&\n \n-\t\tfilter_git checkout --quiet --no-progress . &&\n+\t\tfilter_git checkout --quiet --no-progress -- . &&\n \t\tcat >expected.log <<-EOF &&\n \t\t\tSTART\n \t\t\tinit handshake complete\n@@ -669,7 +669,7 @@ test_expect_success PERL 'process filter abort stops processing of all further f\n \n \t\t# Note: This test assumes that Git filters files in alphabetical\n \t\t# order (\"abort.r\" before \"test.r\").\n-\t\tfilter_git checkout --quiet --no-progress . &&\n+\t\tfilter_git checkout --quiet --no-progress -- . &&\n \t\tcat >expected.log <<-EOF &&\n \t\t\tSTART\n \t\t\tinit handshake complete\n@@ -763,7 +763,7 @@ test_expect_success PERL 'delayed checkout in process filter' '\n \t\ttest_cmp_committed_rot13 \"$TEST_ROOT/test.o\" test-delay10.b &&\n \n \t\trm *.a *.b &&\n-\t\tfilter_git checkout . &&\n+\t\tfilter_git checkout -- . &&\n \t\ttest_cmp_count ../a.exp a.log &&\n \t\ttest_cmp_count ../b.exp b.log &&\n \ndiff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh\nindex beb5927..3587e45 100755\n--- a/t/t0027-auto-crlf.sh\n+++ b/t/t0027-auto-crlf.sh\n@@ -293,9 +293,9 @@ checkout_files () {\n \tdo\n \t\trm crlf_false_attr__$f.txt &&\n \t\tif test -z \"$ceol\"; then\n-\t\t\tgit checkout crlf_false_attr__$f.txt\n+\t\t\tgit checkout -- crlf_false_attr__$f.txt\n \t\telse\n-\t\t\tgit -c core.eol=$ceol checkout crlf_false_attr__$f.txt\n+\t\t\tgit -c core.eol=$ceol checkout -- crlf_false_attr__$f.txt\n \t\tfi\n \tdone\n \ndiff --git a/t/t1011-read-tree-sparse-checkout.sh b/t/t1011-read-tree-sparse-checkout.sh\nindex c167f60..82e0013 100755\n--- a/t/t1011-read-tree-sparse-checkout.sh\n+++ b/t/t1011-read-tree-sparse-checkout.sh\n@@ -257,7 +257,7 @@ test_expect_success 'checkout without --ignore-skip-worktree-bits' '\n \techo sub >.git/info/sparse-checkout &&\n \tgit checkout &&\n \techo modified >> sub/added &&\n-\tgit checkout . &&\n+\tgit checkout -- . &&\n \ttest_path_is_missing init.t &&\n \tgit diff --exit-code HEAD\n '\n@@ -269,7 +269,7 @@ test_expect_success 'checkout with --ignore-skip-worktree-bits' '\n \techo sub >.git/info/sparse-checkout &&\n \tgit checkout &&\n \techo modified >> sub/added &&\n-\tgit checkout --ignore-skip-worktree-bits . &&\n+\tgit checkout --ignore-skip-worktree-bits -- . &&\n \ttest_path_is_file init.t &&\n \tgit diff --exit-code HEAD\n '\ndiff --git a/t/t1050-large.sh b/t/t1050-large.sh\nindex 6fd264c..270bb40 100755\n--- a/t/t1050-large.sh\n+++ b/t/t1050-large.sh\n@@ -89,7 +89,7 @@ test_expect_success 'add a large file or two' '\n test_expect_success 'checkout a large file' '\n \tlarge1=$(git rev-parse :large1) &&\n \tgit update-index --add --cacheinfo 100644 $large1 another &&\n-\tgit checkout another &&\n+\tgit checkout -- another &&\n \ttest_cmp large1 another\n '\n \ndiff --git a/t/t1051-large-conversion.sh b/t/t1051-large-conversion.sh\nindex 8b7640b..7326528 100755\n--- a/t/t1051-large-conversion.sh\n+++ b/t/t1051-large-conversion.sh\n@@ -18,7 +18,7 @@ check_input() {\n \n check_output() {\n \trm -f small large &&\n-\tgit checkout small large &&\n+\tgit checkout -- small large &&\n \thead -n 1 large >large.head &&\n \ttest_cmp small large.head\n }\n@@ -76,7 +76,7 @@ test_expect_success 'user-defined filters convert on output' '\n test_expect_success 'ident converts on output' '\n \tset_attr ident &&\n \trm -f small large &&\n-\tgit checkout small large &&\n+\tgit checkout -- small large &&\n \tsed -n \"s/Id: .*/Id: SHA/p\" <small >small.clean &&\n \thead -n 1 large >large.head &&\n \tsed -n \"s/Id: .*/Id: SHA/p\" <large.head >large.clean &&\ndiff --git a/t/t2009-checkout-statinfo.sh b/t/t2009-checkout-statinfo.sh\nindex f3c2152..0a51b14 100755\n--- a/t/t2009-checkout-statinfo.sh\n+++ b/t/t2009-checkout-statinfo.sh\n@@ -37,13 +37,13 @@ test_expect_success 'path checkout' '\n \tgit reset --hard &&\n \ttest \"$(git diff-files --raw)\" = \"\" &&\n \n-\tgit checkout master world &&\n+\tgit checkout master -- world &&\n \ttest \"$(git diff-files --raw)\" = \"\" &&\n \n-\tgit checkout side world &&\n+\tgit checkout side -- world &&\n \ttest \"$(git diff-files --raw)\" = \"\" &&\n \n-\tgit checkout master world &&\n+\tgit checkout master -- world &&\n \ttest \"$(git diff-files --raw)\" = \"\"\n \n '\ndiff --git a/t/t2010-checkout-ambiguous.sh b/t/t2010-checkout-ambiguous.sh\nindex 2e47fe0..87c8ad2 100755\n--- a/t/t2010-checkout-ambiguous.sh\n+++ b/t/t2010-checkout-ambiguous.sh\n@@ -29,7 +29,7 @@ test_expect_success 'checkout world from the index' '\n '\n \n test_expect_success 'non ambiguous call' '\n-\tgit checkout all\n+\tgit checkout -- all\n '\n \n test_expect_success 'allow the most common case' '\n@@ -44,7 +44,7 @@ test_expect_success 'check ambiguity' '\n test_expect_success 'check ambiguity in subdir' '\n \tmkdir sub &&\n \t# not ambiguous because sub/world does not exist\n-\tgit -C sub checkout world ../all &&\n+\tgit -C sub checkout world -- ../all &&\n \techo hello >sub/world &&\n \t# ambiguous because sub/world does exist\n \ttest_must_fail git -C sub checkout world ../all\ndiff --git a/t/t2013-checkout-submodule.sh b/t/t2013-checkout-submodule.sh\nindex 6ef1573..2581382 100755\n--- a/t/t2013-checkout-submodule.sh\n+++ b/t/t2013-checkout-submodule.sh\n@@ -34,9 +34,9 @@ test_expect_success '\"checkout <submodule>\" updates the index only' '\n \tgit update-index --refresh &&\n \tgit diff-files --quiet &&\n \tgit diff-index --quiet --cached HEAD &&\n-\tgit checkout HEAD^ submodule &&\n+\tgit checkout HEAD^ -- submodule &&\n \ttest_must_fail git diff-files --quiet &&\n-\tgit checkout HEAD submodule &&\n+\tgit checkout HEAD -- submodule &&\n \tgit diff-files --quiet\n '\n \ndiff --git a/t/t2016-checkout-patch.sh b/t/t2016-checkout-patch.sh\nindex 9cd0ac4..c39d2c4 100755\n--- a/t/t2016-checkout-patch.sh\n+++ b/t/t2016-checkout-patch.sh\n@@ -79,13 +79,6 @@ test_expect_success PERL 'git checkout -p handles deletion' '\n # dir/foo.  There's always an extra 'n' to reject edits to dir/foo in\n # the failure case (and thus get out of the loop).\n \n-test_expect_success PERL 'path limiting works: dir' '\n-\tset_state dir/foo work head &&\n-\t(echo y; echo n) | git checkout -p dir &&\n-\tverify_saved_state bar &&\n-\tverify_state dir/foo head head\n-'\n-\n test_expect_success PERL 'path limiting works: -- dir' '\n \tset_state dir/foo work head &&\n \t(echo y; echo n) | git checkout -p -- dir &&\n@@ -103,7 +96,7 @@ test_expect_success PERL 'path limiting works: HEAD^ -- dir' '\n test_expect_success PERL 'path limiting works: foo inside dir' '\n \tset_state dir/foo work head &&\n \t# the third n is to get out in case it mistakenly does not apply\n-\t(echo y; echo n; echo n) | (cd dir && git checkout -p foo) &&\n+\t(echo y; echo n; echo n) | (cd dir && git checkout -p -- foo) &&\n \tverify_saved_state bar &&\n \tverify_state dir/foo head head\n '\ndiff --git a/t/t2022-checkout-paths.sh b/t/t2022-checkout-paths.sh\nindex f46d049..6e254fa 100755\n--- a/t/t2022-checkout-paths.sh\n+++ b/t/t2022-checkout-paths.sh\n@@ -26,7 +26,7 @@ test_expect_success 'checking out paths out of a tree does not clobber unrelated\n \techo untracked >expect.next2 &&\n \tcat expect.next2 >dir/next2 &&\n \n-\tgit checkout master dir &&\n+\tgit checkout master -- dir &&\n \n \ttest_cmp expect.common dir/common &&\n \ttest_path_is_file dir/master &&\n@@ -52,7 +52,7 @@ test_expect_success 'do not touch unmerged entries matching $path but not in $tr\n \tEOF\n \tgit update-index --index-info <expect.next0 &&\n \n-\tgit checkout master dir &&\n+\tgit checkout master -- dir &&\n \n \ttest_cmp expect.common dir/common &&\n \ttest_path_is_file dir/master &&\ndiff --git a/t/t2028-worktree-move.sh b/t/t2028-worktree-move.sh\nindex 5d5b363..3e869e8 100755\n--- a/t/t2028-worktree-move.sh\n+++ b/t/t2028-worktree-move.sh\n@@ -111,7 +111,7 @@ test_expect_success 'remove locked worktree' '\n \n test_expect_success 'remove worktree with dirty tracked file' '\n \techo dirty >>destination/init.t &&\n-\ttest_when_finished \"git -C destination checkout init.t\" &&\n+\ttest_when_finished \"git -C destination checkout -- init.t\" &&\n \ttest_must_fail git worktree remove destination\n '\n \ndiff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh\nindex 309199b..b599c37 100755\n--- a/t/t2030-unresolve-info.sh\n+++ b/t/t2030-unresolve-info.sh\n@@ -108,7 +108,7 @@ test_expect_success 'plumbing clears' '\n test_expect_success 'add records checkout -m undoes' '\n \tprime_resolve_undo &&\n \tgit diff HEAD &&\n-\tgit checkout --conflict=merge fi/le &&\n+\tgit checkout --conflict=merge -- fi/le &&\n \techo checkout used the record and removed it &&\n \tcheck_resolve_undo removed &&\n \techo the index and the work tree is unmerged again &&\n@@ -131,7 +131,7 @@ test_expect_success 'rerere and rerere forget' '\n \trerere_id=$(cd .git/rr-cache && echo */postimage) &&\n \trerere_id=${rerere_id%/postimage} &&\n \ttest -f .git/rr-cache/$rerere_id/postimage &&\n-\tgit checkout -m fi/le &&\n+\tgit checkout -m -- fi/le &&\n \techo resurrect the conflict &&\n \tgrep \"^=======\" fi/le &&\n \techo reresolve the conflict &&\n@@ -157,7 +157,7 @@ test_expect_success 'rerere and rerere forget (subdirectory)' '\n \trerere_id=$(cd .git/rr-cache && echo */postimage) &&\n \trerere_id=${rerere_id%/postimage} &&\n \ttest -f .git/rr-cache/$rerere_id/postimage &&\n-\t(cd fi && git checkout -m le) &&\n+\t(cd fi && git checkout -m -- le) &&\n \techo resurrect the conflict &&\n \tgrep \"^=======\" fi/le &&\n \techo reresolve the conflict &&\ndiff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh\nindex 3fc484e..f376590 100755\n--- a/t/t3001-ls-files-others-exclude.sh\n+++ b/t/t3001-ls-files-others-exclude.sh\n@@ -103,7 +103,7 @@ test_expect_success \\\n      test_cmp expect output'\n \n test_expect_success 'restore gitignore' '\n-\tgit checkout --ignore-skip-worktree-bits $allignores &&\n+\tgit checkout --ignore-skip-worktree-bits -- $allignores &&\n \trm .git/index\n '\n \ndiff --git a/t/t3420-rebase-autostash.sh b/t/t3420-rebase-autostash.sh\nindex e243700..7503b0f 100755\n--- a/t/t3420-rebase-autostash.sh\n+++ b/t/t3420-rebase-autostash.sh\n@@ -345,7 +345,7 @@ test_expect_success 'autostash is saved on editor failure with conflict' '\n \t) &&\n \techo conflicting-content >expected &&\n \ttest_cmp expected file0 &&\n-\tgit checkout file0 &&\n+\tgit checkout -- file0 &&\n \tgit stash pop &&\n \techo uncommitted-content >expected &&\n \ttest_cmp expected file0\ndiff --git a/t/t3510-cherry-pick-sequence.sh b/t/t3510-cherry-pick-sequence.sh\nindex 0acf4b1..742e467 100755\n--- a/t/t3510-cherry-pick-sequence.sh\n+++ b/t/t3510-cherry-pick-sequence.sh\n@@ -52,7 +52,7 @@ test_expect_success 'cherry-pick mid-cherry-pick-sequence' '\n \ttest_must_fail git cherry-pick base..anotherpick &&\n \ttest_cmp_rev picked CHERRY_PICK_HEAD &&\n \t# \"oops, I forgot that these patches rely on the change from base\"\n-\tgit checkout HEAD foo &&\n+\tgit checkout HEAD -- foo &&\n \tgit cherry-pick base &&\n \tgit cherry-pick picked &&\n \tgit cherry-pick --continue &&\n@@ -205,7 +205,7 @@ test_expect_success '--abort refuses to clobber unrelated change, harder case' '\n \ttest_line_count = 2 log &&\n \ttest_must_fail git update-index --refresh &&\n \n-\tgit checkout unrelated &&\n+\tgit checkout -- unrelated &&\n \tgit cherry-pick --abort &&\n \ttest_cmp_rev initial HEAD\n '\ndiff --git a/t/t3910-mac-os-precompose.sh b/t/t3910-mac-os-precompose.sh\nindex 26dd5b7..6932f20 100755\n--- a/t/t3910-mac-os-precompose.sh\n+++ b/t/t3910-mac-os-precompose.sh\n@@ -141,9 +141,9 @@ test_expect_success \"git checkout nfc\" '\n \tgit checkout f.$Odiarnfc\n '\n # Make it possible to checkout files with their NFD names\n-test_expect_success \"git checkout file nfd\" '\n+test_expect_success \"git checkout -- file nfd\" '\n \trm -f f.* &&\n-\tgit checkout f.$Odiarnfd\n+\tgit checkout -- f.$Odiarnfd\n '\n # Make it possible to checkout links with their NFD names\n test_expect_success \"git checkout link nfd\" '\ndiff --git a/t/t4015-diff-whitespace.sh b/t/t4015-diff-whitespace.sh\nindex 17df491..90da499 100755\n--- a/t/t4015-diff-whitespace.sh\n+++ b/t/t4015-diff-whitespace.sh\n@@ -552,7 +552,7 @@ test_expect_success 'check with space before tab in indent' '\n '\n \n test_expect_success '--check and --exit-code are not exclusive' '\n-\tgit checkout x &&\n+\tgit checkout -- x &&\n \tgit diff --check --exit-code\n '\n \n@@ -769,7 +769,7 @@ test_expect_success 'checkdiff detects new trailing blank lines (2)' '\n '\n \n test_expect_success 'checkdiff allows new blank lines' '\n-\tgit checkout x &&\n+\tgit checkout -- x &&\n \tmv x y &&\n \t(\n \t\techo \"/* This is new */\" &&\ndiff --git a/t/t4117-apply-reject.sh b/t/t4117-apply-reject.sh\nindex d80187d..e97dfa5 100755\n--- a/t/t4117-apply-reject.sh\n+++ b/t/t4117-apply-reject.sh\n@@ -49,7 +49,7 @@ test_expect_success setup '\n test_expect_success 'apply --reject is incompatible with --3way' '\n \ttest_when_finished \"cat saved.file1 >file1\" &&\n \tgit diff >patch.0 &&\n-\tgit checkout file1 &&\n+\tgit checkout -- file1 &&\n \ttest_must_fail git apply --reject --3way patch.0 &&\n \tgit diff --exit-code\n '\ndiff --git a/t/t4124-apply-ws-rule.sh b/t/t4124-apply-ws-rule.sh\nindex 4fc27c5..ae5ace7 100755\n--- a/t/t4124-apply-ws-rule.sh\n+++ b/t/t4124-apply-ws-rule.sh\n@@ -223,7 +223,7 @@ test_expect_success 'blank at EOF with --whitespace=fix (1)' '\n \t{ cat expect; echo; } >one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=fix patch &&\n \ttest_cmp expect one\n '\n@@ -235,7 +235,7 @@ test_expect_success 'blank at EOF with --whitespace=fix (2)' '\n \t{ cat expect; echo; echo; } >one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=fix patch &&\n \ttest_cmp expect one\n '\n@@ -247,7 +247,7 @@ test_expect_success 'blank at EOF with --whitespace=fix (3)' '\n \t{ cat expect; echo; echo; } >one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=fix patch &&\n \ttest_cmp expect one\n '\n@@ -259,7 +259,7 @@ test_expect_success 'blank at end of hunk, not at EOF with --whitespace=fix' '\n \tcp expect one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=fix patch &&\n \ttest_cmp expect one\n '\n@@ -271,7 +271,7 @@ test_expect_success 'blank at EOF with --whitespace=warn' '\n \tcat one >expect &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=warn patch 2>error &&\n \ttest_cmp expect one &&\n \tgrep \"new blank line at EOF\" error\n@@ -284,7 +284,7 @@ test_expect_success 'blank at EOF with --whitespace=error' '\n \techo >>one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \ttest_must_fail git apply --whitespace=error patch 2>error &&\n \ttest_cmp expect one &&\n \tgrep \"new blank line at EOF\" error\n@@ -297,7 +297,7 @@ test_expect_success 'blank but not empty at EOF' '\n \tcat one >expect &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \tgit apply --whitespace=warn patch 2>error &&\n \ttest_cmp expect one &&\n \tgrep \"new blank line at EOF\" error\n@@ -309,7 +309,7 @@ test_expect_success 'applying beyond EOF requires one non-blank context line' '\n \t{ echo b; } >>one &&\n \tgit diff -- one >patch &&\n \n-\tgit checkout one &&\n+\tgit checkout -- one &&\n \t{ echo a; echo; } >one &&\n \tcp one expect &&\n \ttest_must_fail git apply --whitespace=fix patch &&\ndiff --git a/t/t5403-post-checkout-hook.sh b/t/t5403-post-checkout-hook.sh\nindex fc898c9..f72ee38 100755\n--- a/t/t5403-post-checkout-hook.sh\n+++ b/t/t5403-post-checkout-hook.sh\n@@ -64,7 +64,7 @@ test_expect_success 'post-checkout receives the right args with HEAD changed ' '\n '\n \n test_expect_success 'post-checkout receives the right args when not switching branches ' '\n-\tGIT_DIR=clone2/.git git checkout master b &&\n+\tGIT_DIR=clone2/.git git checkout master -- b &&\n \told=$(awk \"{print \\$1}\" clone2/.git/post-checkout.args) &&\n \tnew=$(awk \"{print \\$2}\" clone2/.git/post-checkout.args) &&\n \tflag=$(awk \"{print \\$3}\" clone2/.git/post-checkout.args) &&\ndiff --git a/t/t6007-rev-list-cherry-pick-file.sh b/t/t6007-rev-list-cherry-pick-file.sh\nindex f026837..e5b0daa 100755\n--- a/t/t6007-rev-list-cherry-pick-file.sh\n+++ b/t/t6007-rev-list-cherry-pick-file.sh\n@@ -32,7 +32,7 @@ test_expect_success setup '\n \tgit commit -m \"E\" &&\n \tgit tag E &&\n \tgit checkout master &&\n-\tgit checkout branch foo &&\n+\tgit checkout branch -- foo &&\n \ttest_tick &&\n \tgit commit -m \"B\" &&\n \tgit tag B &&\ndiff --git a/t/t6026-merge-attr.sh b/t/t6026-merge-attr.sh\nindex 8f9b48a..4aae0e9 100755\n--- a/t/t6026-merge-attr.sh\n+++ b/t/t6026-merge-attr.sh\n@@ -72,7 +72,7 @@ test_expect_success 'check merge result in working tree' '\n \n test_expect_success 'retry the merge with longer context' '\n \techo text conflict-marker-size=32 >>.gitattributes &&\n-\tgit checkout -m text &&\n+\tgit checkout -m -- text &&\n \tsed -ne \"/^\\([<=>]\\)\\1\\1\\1*/{\n \t\ts/ .*$//\n \t\tp\ndiff --git a/t/t6030-bisect-porcelain.sh b/t/t6030-bisect-porcelain.sh\nindex f84ff94..7104f08 100755\n--- a/t/t6030-bisect-porcelain.sh\n+++ b/t/t6030-bisect-porcelain.sh\n@@ -177,7 +177,7 @@ test_expect_success 'bisect start: no \".git/BISECT_START\" if checkout error' '\n \tgrep \"* other\" branch.output > /dev/null &&\n \ttest_must_fail test -e .git/BISECT_START &&\n \ttest -z \"$(git for-each-ref \"refs/bisect/*\")\" &&\n-\tgit checkout HEAD hello\n+\tgit checkout HEAD -- hello\n '\n \n # $HASH1 is good, $HASH4 is bad, we skip $HASH3\ndiff --git a/t/t6038-merge-text-auto.sh b/t/t6038-merge-text-auto.sh\nindex 5e8d5fa..2e2979b 100755\n--- a/t/t6038-merge-text-auto.sh\n+++ b/t/t6038-merge-text-auto.sh\n@@ -51,7 +51,7 @@ test_expect_success setup '\n \n \tgit rm .gitattributes &&\n \trm file &&\n-\tgit checkout file &&\n+\tgit checkout -- file &&\n \ttest_tick &&\n \tgit commit -m \"remove .gitattributes\" &&\n \tgit tag c &&\ndiff --git a/t/t6050-replace.sh b/t/t6050-replace.sh\nindex c630aba..0bea83c 100755\n--- a/t/t6050-replace.sh\n+++ b/t/t6050-replace.sh\n@@ -292,7 +292,7 @@ test_expect_success 'not just commits' '\n \tgit update-ref refs/replace/$ORIGINAL $REPLACED &&\n \tmv file file.original &&\n \n-\tgit checkout file &&\n+\tgit checkout -- file &&\n \ttest_cmp file.replaced file\n '\n \ndiff --git a/t/t6111-rev-list-treesame.sh b/t/t6111-rev-list-treesame.sh\nindex 32474c2..bc46a77 100755\n--- a/t/t6111-rev-list-treesame.sh\n+++ b/t/t6111-rev-list-treesame.sh\n@@ -43,7 +43,7 @@ test_expect_success setup '\n \ttest_commit \"file=Blah\" file \"Blah\" F &&\n \n \ttest_tick && git merge --no-commit third-branch &&\n-\tgit checkout third-branch file &&\n+\tgit checkout third-branch -- file &&\n \tgit commit &&\n \tnote G &&\n \tgit branch fiddler-branch &&\ndiff --git a/t/t7001-mv.sh b/t/t7001-mv.sh\nindex d4e6485..f46903f 100755\n--- a/t/t7001-mv.sh\n+++ b/t/t7001-mv.sh\n@@ -481,7 +481,7 @@ test_expect_success 'mv -k does not accidentally destroy submodules' '\n \tgit status --porcelain >actual &&\n \tgrep \"^R  sub -> dest/sub\" actual &&\n \tgit reset --hard &&\n-\tgit checkout .\n+\tgit checkout -- .\n '\n \n test_expect_success 'moving a submodule in nested directories' '\ndiff --git a/t/t7008-grep-binary.sh b/t/t7008-grep-binary.sh\nindex 615e7e0..de19773 100755\n--- a/t/t7008-grep-binary.sh\n+++ b/t/t7008-grep-binary.sh\n@@ -192,7 +192,7 @@ test_expect_success 'grep --cached respects binary diff attribute (2)' '\n \trm .gitattributes &&\n \tgit grep --cached text t >actual &&\n \ttest_when_finished \"git rm --cached .gitattributes\" &&\n-\ttest_when_finished \"git checkout .gitattributes\" &&\n+\ttest_when_finished \"git checkout -- .gitattributes\" &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t7201-co.sh b/t/t7201-co.sh\nindex 76c223c..65a3d24 100755\n--- a/t/t7201-co.sh\n+++ b/t/t7201-co.sh\n@@ -498,7 +498,7 @@ test_expect_success 'checkout with an unmerged path can be ignored' '\n \tcat sample >fild &&\n \tcat sample >file &&\n \tcat sample >filf &&\n-\tgit checkout -f fild file filf &&\n+\tgit checkout -f -- fild file filf &&\n \ttest_cmp expect fild &&\n \ttest_cmp expect filf &&\n \ttest_cmp sample file\n@@ -511,11 +511,11 @@ test_expect_success 'checkout unmerged stage' '\n \tcat sample >fild &&\n \tcat sample >file &&\n \tcat sample >filf &&\n-\tgit checkout --ours . &&\n+\tgit checkout --ours -- . &&\n \ttest_cmp expect fild &&\n \ttest_cmp expect filf &&\n \ttest_cmp expect file &&\n-\tgit checkout --theirs file &&\n+\tgit checkout --theirs -- file &&\n \ttest ztheirside = \"z$(cat file)\"\n '\n \n@@ -677,7 +677,7 @@ test_expect_success 'custom merge driver with checkout -m' '\n \t) &&\n \n \tmv arm expect &&\n-\tgit checkout -m arm &&\n+\tgit checkout -m -- arm &&\n \ttest_cmp expect arm\n '\n \ndiff --git a/t/t7300-clean.sh b/t/t7300-clean.sh\nindex 7b36954..7b22454 100755\n--- a/t/t7300-clean.sh\n+++ b/t/t7300-clean.sh\n@@ -38,7 +38,7 @@ test_expect_success 'git clean with skip-worktree .gitignore' '\n \ttest -f obj.o &&\n \ttest -f build/lib.so &&\n \tgit update-index --no-skip-worktree .gitignore &&\n-\tgit checkout .gitignore\n+\tgit checkout -- .gitignore\n '\n \n test_expect_success 'git clean' '\ndiff --git a/t/t7501-commit.sh b/t/t7501-commit.sh\nindex fa61b1a..bae0137 100755\n--- a/t/t7501-commit.sh\n+++ b/t/t7501-commit.sh\n@@ -30,12 +30,12 @@ test_expect_success 'setup: initial commit' '\n '\n \n test_expect_success '-m and -F do not mix' '\n-\tgit checkout HEAD file && echo >>file && git add file &&\n+\tgit checkout HEAD -- file && echo >>file && git add file &&\n \ttest_must_fail git commit -m foo -m bar -F file\n '\n \n test_expect_success '-m and -C do not mix' '\n-\tgit checkout HEAD file && echo >>file && git add file &&\n+\tgit checkout HEAD -- file && echo >>file && git add file &&\n \ttest_must_fail git commit -C HEAD -m illegal\n '\n \n@@ -119,18 +119,18 @@ test_expect_success 'empty commit message' '\n '\n \n test_expect_success 'template \"emptyness\" check does not kick in with -F' '\n-\tgit checkout HEAD file && echo >>file && git add file &&\n+\tgit checkout HEAD -- file && echo >>file && git add file &&\n \tgit commit -t file -F file\n '\n \n test_expect_success 'template \"emptyness\" check' '\n-\tgit checkout HEAD file && echo >>file && git add file &&\n+\tgit checkout HEAD -- file && echo >>file && git add file &&\n \ttest_must_fail git commit -t file 2>err &&\n \ttest_i18ngrep \"did not edit\" err\n '\n \n test_expect_success 'setup: commit message from file' '\n-\tgit checkout HEAD file && echo >>file && git add file &&\n+\tgit checkout HEAD -- file && echo >>file && git add file &&\n \techo this is the commit message, coming from a file >msg &&\n \tgit commit -F msg -a\n '\ndiff --git a/t/t7502-commit.sh b/t/t7502-commit.sh\nindex d33a3cb..ec8df56 100755\n--- a/t/t7502-commit.sh\n+++ b/t/t7502-commit.sh\n@@ -470,7 +470,7 @@ test_expect_success 'Hand committing of a redundant merge removes dups' '\n \n \tgit rev-parse second master >expect &&\n \ttest_must_fail git merge second master &&\n-\tgit checkout master g &&\n+\tgit checkout master -- g &&\n \tEDITOR=: git commit -a &&\n \tgit cat-file commit HEAD | sed -n -e \"s/^parent //p\" -e \"/^$/q\" >actual &&\n \ttest_cmp expect actual\ndiff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh\nindex 9c422bc..5e2ea53 100755\n--- a/t/t7607-merge-overwrite.sh\n+++ b/t/t7607-merge-overwrite.sh\n@@ -55,7 +55,7 @@ test_expect_success 'will not overwrite staged changes' '\n \trm c2.c &&\n \ttest_must_fail git merge c2 &&\n \ttest_path_is_missing .git/MERGE_HEAD &&\n-\tgit checkout c2.c &&\n+\tgit checkout -- c2.c &&\n \ttest_cmp important c2.c\n '\n \n@@ -88,7 +88,7 @@ test_expect_success 'will not overwrite removed file with staged changes' '\n \trm c1.c &&\n \ttest_must_fail git merge c1a &&\n \ttest_path_is_missing .git/MERGE_HEAD &&\n-\tgit checkout c1.c &&\n+\tgit checkout -- c1.c &&\n \ttest_cmp important c1.c\n '\n \ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 1797f63..8d00cc6 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -714,7 +714,7 @@ test_expect_success 'grep with CE_VALID file' '\n \trm t/t &&\n \ttest \"$(git grep test)\" = \"t/t:test\" &&\n \tgit update-index --no-assume-unchanged t/t &&\n-\tgit checkout t/t\n+\tgit checkout -- t/t\n '\n \n cat >expected <<EOF\ndiff --git a/t/t7811-grep-open.sh b/t/t7811-grep-open.sh\nindex e1951a5..e0e0fbf 100755\n--- a/t/t7811-grep-open.sh\n+++ b/t/t7811-grep-open.sh\n@@ -119,7 +119,7 @@ test_expect_success 'modified file' '\n \t>empty &&\n \n \techo \"enum grep_pat_token\" >unrelated &&\n-\ttest_when_finished \"git checkout HEAD unrelated\" &&\n+\ttest_when_finished \"git checkout HEAD -- unrelated\" &&\n \tGIT_PAGER=./less git grep -F -O \"enum grep_pat_token\" >out &&\n \ttest_cmp expect actual &&\n \ttest_cmp empty out\ndiff --git a/t/t8003-blame-corner-cases.sh b/t/t8003-blame-corner-cases.sh\nindex 661f9d4..da3f98f 100755\n--- a/t/t8003-blame-corner-cases.sh\n+++ b/t/t8003-blame-corner-cases.sh\n@@ -265,7 +265,7 @@ test_expect_success 'blame file with CRLF core.autocrlf=true' '\n \tgit commit -m \"add crlfinrepo\" &&\n \tgit config core.autocrlf true &&\n \tmv crlfinrepo tmp &&\n-\tgit checkout crlfinrepo &&\n+\tgit checkout -- crlfinrepo &&\n \trm tmp &&\n \tgit blame crlfinrepo >actual &&\n \tgrep \"A U Thor\" actual\ndiff --git a/t/t8006-blame-textconv.sh b/t/t8006-blame-textconv.sh\nindex 7683515..a81d677 100755\n--- a/t/t8006-blame-textconv.sh\n+++ b/t/t8006-blame-textconv.sh\n@@ -73,7 +73,7 @@ test_expect_success 'blame --textconv going through revisions' '\n '\n \n test_expect_success 'blame --textconv with local changes' '\n-\ttest_when_finished \"git checkout zero.bin\" &&\n+\ttest_when_finished \"git checkout -- zero.bin\" &&\n \tprintf \"bin: updated number 0\\015\" >zero.bin &&\n \tgit blame --textconv zero.bin >blame &&\n \texpect=\"(Not Committed Yet ....-..-.. ..:..:.. +0000 1)\" &&\ndiff --git a/t/t9010-svn-fe.sh b/t/t9010-svn-fe.sh\nindex 8eaaca6..ba54fb2 100755\n--- a/t/t9010-svn-fe.sh\n+++ b/t/t9010-svn-fe.sh\n@@ -258,7 +258,7 @@ test_expect_success 'directory with files' '\n \ttry_dump directory.dump &&\n \n \tgit ls-tree -r --name-only HEAD >actual.files &&\n-\tgit checkout HEAD directory &&\n+\tgit checkout HEAD -- directory &&\n \ttest_cmp expect.files actual.files &&\n \ttest_cmp hello directory/file1 &&\n \ttest_cmp hi directory/file2\n-- \n2.7.4\n\n"},{"id":"347482","messageId":"1526178214-30956-3-git-send-email-danniercl@gmail.com","threadId":"48476","inReplyTo":"1526178214-30956-1-git-send-email-danniercl@gmail.com","subject":"[PATCH 3/3] doc: update doc for strict usage of -- checkout","fromName":"Dannier Castro L","fromEmail":"danniercl@gmail.com","sentAt":"2018-05-13T02:23:34Z","receivedAt":"2018-05-13T02:24:23Z","isPatch":true,"sender":{"key":"danniercl@gmail.com","avatar":null},"body":"The flag '--' must always be before any file path when <checkout>\ncommand is used.\n\nThe main documentation about the usage of <checkout> command is\nupdated to include the strict usage of the flag '--' so that the\nuser can specify file names over branch names.\n\nSigned-off-by: Dannier Castro L <danniercl@gmail.com>:\n---\n Documentation/git-checkout.txt | 20 ++++++--------------\n 1 file changed, 6 insertions(+), 14 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex ca5fc9c..8360a98 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -12,9 +12,9 @@ SYNOPSIS\n 'git checkout' [-q] [-f] [-m] --detach [<branch>]\n 'git checkout' [-q] [-f] [-m] [--detach] <commit>\n 'git checkout' [-q] [-f] [-m] [[-b|-B|--orphan] <new_branch>] [<start_point>]\n-'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...\n-'git checkout' [<tree-ish>] [--] <pathspec>...\n-'git checkout' (-p|--patch) [<tree-ish>] [--] [<paths>...]\n+'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] -- <paths>...\n+'git checkout' [<tree-ish>] -- <pathspec>...\n+'git checkout' (-p|--patch) [<tree-ish>] [-- <paths>...]\n \n DESCRIPTION\n -----------\n@@ -79,7 +79,7 @@ be used to detach HEAD at the tip of the branch (`git checkout\n +\n Omitting <branch> detaches HEAD at the tip of the current branch.\n \n-'git checkout' [<tree-ish>] [--] <pathspec>...::\n+'git checkout' [<tree-ish>] -- <pathspec>...::\n \n \tOverwrite paths in the working tree by replacing with the\n \tcontents in the index or in the <tree-ish> (most often a\n@@ -95,7 +95,7 @@ specific side of the merge can be checked out of the index by\n using `--ours` or `--theirs`.  With `-m`, changes made to the working tree\n file can be discarded to re-create the original conflicted merge result.\n \n-'git checkout' (-p|--patch) [<tree-ish>] [--] [<pathspec>...]::\n+'git checkout' (-p|--patch) [<tree-ish>] [-- <pathspec>...]::\n \tThis is similar to the \"check out paths to the working tree\n \tfrom either the index or from a tree-ish\" mode described\n \tabove, but lets you use the interactive interface to show\n@@ -453,7 +453,7 @@ mistake, and gets it back from the index.\n $ git checkout master             <1>\n $ git checkout master~2 Makefile  <2>\n $ rm -f hello.c\n-$ git checkout hello.c            <3>\n+$ git checkout -- hello.c         <3>\n ------------\n +\n <1> switch branch\n@@ -471,14 +471,6 @@ Note the quotes around `*.c`.  The file `hello.c` will also be\n checked out, even though it is no longer in the working tree,\n because the file globbing is used to match entries in the index\n (not in the working tree by the shell).\n-+\n-If you have an unfortunate branch that is named `hello.c`, this\n-step would be confused as an instruction to switch to that branch.\n-You should instead write:\n-+\n-------------\n-$ git checkout -- hello.c\n-------------\n \n . After working in the wrong branch, switching to the correct\n branch would be done using:\n-- \n2.7.4\n\n"},{"id":"347528","messageId":"CACsJy8DZ1QvjO+JdbB76TOLtB2wp4Ya+CgsTyD1oz2Y+ZdKdYQ@mail.gmail.com","threadId":"48476","inReplyTo":"1526178214-30956-1-git-send-email-danniercl@gmail.com","subject":"Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-13T06:03:24Z","receivedAt":"2018-05-13T06:04:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, May 13, 2018 at 4:23 AM, Dannier Castro L <danniercl@gmail.com> wrote:\n> Currently, <checkout> is a complex command able to handle both\n> branches and files without any distintion other than their names,\n> taking into account that depending on the type (branch or file),\n> the functionality is completely different, the easier example:\n>\n> $ git checkout <branch>  # Switch from current branch to <branch>.\n> $ git checkout <file>    # Restore <file> from HEAD, discarding\n>                          # changes if it's necessary.\n> $ git checkout -- <file> # The same as the last one, only with an\n>                          # useless '--'.\n>\n> For GIT new users, this complicated versatility of <checkout> could\n> be very confused, also considering that actually the flag '--' is\n> completely useless (added or not, there is not any difference for\n> this command), when the same program messages promote the use of\n> this flag.\n\nI would like an option to revert back to current behavior. I'm not a\nnew user. I know what I'm doing. Please don't make me type more.\n\nAnd '--\" is not completely useless. If you have <file> and <branch>\nwith the same name, you have to give \"--\" to to tell git what the\nfirst argument means.\n\n> Regarding the <checkout>'s power to overwrite any file, discarding\n> changes if they exist without some way of recovering them, the\n> solution propuses that the usage of '--' is strict before to\n> specify the file(s) path(s) for any <checkout> command (including\n> all types of flags), as a \"defense barrier\" to make sure about\n> user's knowledge and intension running <checkout>.\n>\n> The solution consists in detect '--' into command args, allowing\n> the discard of changes and considering the following names as\n> file paths, otherwise, they are branch names.\n-- \nDuy\n"},{"id":"347553","messageId":"775fe020-be92-f65c-5a67-e83e6bf4777f@gmail.com","threadId":"48476","inReplyTo":"CACsJy8DZ1QvjO+JdbB76TOLtB2wp4Ya+CgsTyD1oz2Y+ZdKdYQ@mail.gmail.com","subject":"Re: Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Dannier Castro L","fromEmail":"danniercl@gmail.com","sentAt":"2018-05-13T19:11:41Z","receivedAt":"2018-05-13T19:11:49Z","isPatch":true,"sender":{"key":"danniercl@gmail.com","avatar":null},"body":"On 13/05/2018 00:03, Duy Nguyen wrote:\n\n> On Sun, May 13, 2018 at 4:23 AM, Dannier Castro L <danniercl@gmail.com> wrote:\n>> For GIT new users, this complicated versatility of <checkout> could\n>> be very confused, also considering that actually the flag '--' is\n>> completely useless (added or not, there is not any difference for\n>> this command), when the same program messages promote the use of\n>> this flag.\n> I would like an option to revert back to current behavior. I'm not a\n> new user. I know what I'm doing. Please don't make me type more.\n>\n> And '--\" is not completely useless. If you have <file> and <branch>\n> with the same name, you have to give \"--\" to to tell git what the\n> first argument means.\n\nSure Duy, you're right, probably \"completely useless\" is not the correct\ndefinition, even according with the code I didn't find another useful\ncase that is not file and branch with the same name. The program is able\nto know the type using only the name, turning \"--\" into an extra flag in\nmost of cases.\n\nI think this solution could please you more: By default the configuration\nis the current, but the user has the chance to set this, for example:\n\ngit config --global flag.strictdashdash true\n\nThank you so much for the spent time reviewing the patch, this is my\nfirst one in this repository.\n\n-Dannier CL\n\n"},{"id":"347554","messageId":"20180513201810.6440-1-szeder.dev@gmail.com","threadId":"48476","inReplyTo":"775fe020-be92-f65c-5a67-e83e6bf4777f@gmail.com","subject":"Re: Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2018-05-13T20:18:10Z","receivedAt":"2018-05-13T20:18:21Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"> On 13/05/2018 00:03, Duy Nguyen wrote:\n> \n> > On Sun, May 13, 2018 at 4:23 AM, Dannier Castro L <danniercl@gmail.com> wrote:\n> >> For GIT new users, this complicated versatility of <checkout> could\n> >> be very confused, also considering that actually the flag '--' is\n> >> completely useless (added or not, there is not any difference for\n> >> this command), when the same program messages promote the use of\n> >> this flag.\n> > I would like an option to revert back to current behavior. I'm not a\n> > new user. I know what I'm doing. Please don't make me type more.\n> >\n> > And '--\" is not completely useless. If you have <file> and <branch>\n> > with the same name, you have to give \"--\" to to tell git what the\n> > first argument means.\n> \n> Sure Duy, you're right, probably \"completely useless\" is not the correct\n> definition,\n\nNo, \"completely useless\" is just plain wrong.\n\n> even according with the code I didn't find another useful\n> case that is not file and branch with the same name.\n\nThe optional disambiguating doubledash is the standard way to erm, well,\nto disambiguate whatever there is to disambiguate.  Not only refs and\nfilenames, but also e.g. options and filenames:\n\n  $ git checkout --option-looking-file\n  error: unknown option `option-looking-file'\n  usage: git checkout [<options>] <branch>\n  <...>\n  $ git checkout -- --option-looking-file\n  error: pathspec '--option-looking-file' did not match any file(s) known to git.\n\nNote that this is not at all specific to Git, many other programs\nsupport the optional disambiguating doubledash as well:\n\n  $ touch --option-looking-file\n  touch: unrecognized option '--option-looking-file'\n  Try 'touch --help' for more information.\n  $ touch -- --option-looking-file\n  $ ls --option-looking-file\n  ls: unrecognized option '--option-looking-file'\n  Try 'ls --help' for more information.\n  $ ls -- --option-looking-file\n  --option-looking-file\n\nPlease do not make it mandatory.\n\n"},{"id":"347555","messageId":"20180513210233.GA18892@alpha","threadId":"48476","inReplyTo":"1526178214-30956-1-git-send-email-danniercl@gmail.com","subject":"Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Kevin Daudt","fromEmail":"me@ikke.info","sentAt":"2018-05-13T21:02:33Z","receivedAt":"2018-05-13T21:02:38Z","isPatch":true,"sender":{"key":"me@ikke.info","avatar":"https://avatars.githubusercontent.com/u/135698?v=4"},"body":"On Sat, May 12, 2018 at 08:23:32PM -0600, Dannier Castro L wrote:\n> Currently, <checkout> is a complex command able to handle both\n> branches and files without any distintion other than their names,\n> taking into account that depending on the type (branch or file),\n> the functionality is completely different, the easier example:\n> \n> $ git checkout <branch>  # Switch from current branch to <branch>.\n> $ git checkout <file>    # Restore <file> from HEAD, discarding\n>                          # changes if it's necessary.\n> $ git checkout -- <file> # The same as the last one, only with an\n>                          # useless '--'.\n> \n> For GIT new users, this complicated versatility of <checkout> could\n> be very confused, also considering that actually the flag '--' is\n> completely useless (added or not, there is not any difference for\n> this command), when the same program messages promote the use of\n> this flag.\n> \n> Regarding the <checkout>'s power to overwrite any file, discarding\n> changes if they exist without some way of recovering them, the\n> solution propuses that the usage of '--' is strict before to\n> specify the file(s) path(s) for any <checkout> command (including\n> all types of flags), as a \"defense barrier\" to make sure about\n> user's knowledge and intension running <checkout>.\n> \n> The solution consists in detect '--' into command args, allowing\n> the discard of changes and considering the following names as\n> file paths, otherwise, they are branch names.\n> \n> Signed-off-by: Dannier Castro L <danniercl@gmail.com>\n\nOne data point indicating this is giving issues is that today on IRC a\nuser was confused why `git checkout pt` did not show any message and did\nnot checkout a remote branch called 'pt' as they expected. It turned out\nthey also had a local file/dir called 'pt', which caused git to checkout\nthat file/dir rather than creating a local branch based on the remote\nbranch.\n\nKevin\n"},{"id":"347557","messageId":"190EC44928954138B9E9E78BA2323639@PhilipOakley","threadId":"48476","inReplyTo":"775fe020-be92-f65c-5a67-e83e6bf4777f@gmail.com","subject":"Re: Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2018-05-13T23:06:56Z","receivedAt":"2018-05-13T23:07:12Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"From: \"Dannier Castro L\" <danniercl@gmail.com>\n> On 13/05/2018 00:03, Duy Nguyen wrote:\n>\n>> On Sun, May 13, 2018 at 4:23 AM, Dannier Castro L <danniercl@gmail.com>\n>> wrote:\n>>> For GIT new users, this complicated versatility of <checkout> could\n>>> be very confused, also considering that actually the flag '--' is\n>>> completely useless (added or not, there is not any difference for\n>>> this command), when the same program messages promote the use of\n>>> this flag.\n>> I would like an option to revert back to current behavior. I'm not a\n>> new user. I know what I'm doing. Please don't make me type more.\n>>\n>> And '--\" is not completely useless. If you have <file> and <branch>\n>> with the same name, you have to give \"--\" to to tell git what the\n>> first argument means.\n>\n> Sure Duy, you're right, probably \"completely useless\" is not the correct\n> definition, even according with the code I didn't find another useful\n> case that is not file and branch with the same name. The program is able\n> to know the type using only the name, turning \"--\" into an extra flag in\n> most of cases.\n>\n> I think this solution could please you more: By default the configuration\n> is the current, but the user has the chance to set this, for example:\n>\n> git config --global flag.strictdashdash true\n>\n> Thank you so much for the spent time reviewing the patch, this is my\n> first one in this repository.\n\nIt maybe that after review you could suggest an appropriate rewording or\nre-arrangement of the man page to better highlight the proper use of the\n'--' disambiguation.\n\nPerhaps frame the man page as if it is normal for the '--' to be included\nwithin command lines (which should be the case for scripts anyway!).\n\nThen indicate that it isn't mandatory if the file/branch/dwim distinction is\nobvious. i.e. make sure that the man page is educational as well as being a\nreference that may be misunderstood.\n\nThose well versed in the Git cli will normally omit the '--', only using it\nwhere necessary, however for a new users/readers of the man page, it may be\nbetter to be more explicit and avoid future misunderstandings.\n\n--\nPhilip\n\n"},{"id":"347563","messageId":"xmqqsh6vc8do.fsf@gitster-ct.c.googlers.com","threadId":"48476","inReplyTo":"CACsJy8DZ1QvjO+JdbB76TOLtB2wp4Ya+CgsTyD1oz2Y+ZdKdYQ@mail.gmail.com","subject":"Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-14T01:51:15Z","receivedAt":"2018-05-14T01:51:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Duy Nguyen <pclouds@gmail.com> writes:\n\n>\n> I would like an option to revert back to current behavior. I'm not a\n> new user. I know what I'm doing. Please don't make me type more.\n\nI can guarantee that nobody will stay a newbie.  They either become\nmore proficient and aware of what they are doing without having to\nthink, at which point they start feeling the same way as you are.\nOr they leave the Git ecosystem and move to better things ;-)\n\n> And '--\" is not completely useless. If you have <file> and <branch>\n> with the same name, you have to give \"--\" to to tell git what the\n> first argument means.\n\nCorrect.\n\nWe _could_ do better than the corrent code, though, when we happen\nto have a file called 'master'.  \"git checkout master master\" cannot\nmean anything other than \"I want to make the index and the working\ntree copies of 'master' file to match what is recorded on the master\nbranch\", but I think we do require \"git checkout master -- master\"\ndisambiguation.\n\n"},{"id":"347603","messageId":"CACsJy8B2TVr1g+k+eSQ=pBEO3WN4_LtgLo9gpur8X7Z9GOFL_A@mail.gmail.com","threadId":"48476","inReplyTo":"20180513210233.GA18892@alpha","subject":"Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-14T14:52:53Z","receivedAt":"2018-05-14T14:53:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Sun, May 13, 2018 at 11:02 PM, Kevin Daudt <me@ikke.info> wrote:\n> One data point indicating this is giving issues is that today on IRC a\n> user was confused why `git checkout pt` did not show any message and did\n> not checkout a remote branch called 'pt' as they expected. It turned out\n> they also had a local file/dir called 'pt', which caused git to checkout\n> that file/dir rather than creating a local branch based on the remote\n> branch.\n\nNow this is something we should fix. When an argument can be\ninterpreted in more than one way Git should reject it, but I think\nthis ambiguation logic does not take dwim (i.e. create a new branch\nbeased on remote) into account.\n-- \nDuy\n"},{"id":"347604","messageId":"20180514154319.GA424@duynguyen.home","threadId":"48476","inReplyTo":"CACsJy8B2TVr1g+k+eSQ=pBEO3WN4_LtgLo9gpur8X7Z9GOFL_A@mail.gmail.com","subject":"Re: [PATCH 1/3] checkout.c: add strict usage of -- before file_path","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-14T15:43:19Z","receivedAt":"2018-05-14T15:43:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, May 14, 2018 at 04:52:53PM +0200, Duy Nguyen wrote:\n> On Sun, May 13, 2018 at 11:02 PM, Kevin Daudt <me@ikke.info> wrote:\n> > One data point indicating this is giving issues is that today on IRC a\n> > user was confused why `git checkout pt` did not show any message and did\n> > not checkout a remote branch called 'pt' as they expected. It turned out\n> > they also had a local file/dir called 'pt', which caused git to checkout\n> > that file/dir rather than creating a local branch based on the remote\n> > branch.\n> \n> Now this is something we should fix. When an argument can be\n> interpreted in more than one way Git should reject it, but I think\n> this ambiguation logic does not take dwim (i.e. create a new branch\n> beased on remote) into account.\n\nThis is a quick draft to make this happen\n\n-- 8< --\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex b49b582071..f4f6951f05 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -953,8 +953,19 @@ static int parse_branchname_arg(int argc, const char **argv,\n \t\t */\n \t\tint recover_with_dwim = dwim_new_local_branch_ok;\n \n-\t\tif (!has_dash_dash &&\n-\t\t    (check_filename(opts->prefix, arg) || !no_wildcard(arg)))\n+\t\tif (!has_dash_dash && check_filename(opts->prefix, arg) &&\n+\t\t    recover_with_dwim) {\n+\t\t\tconst char *remote = unique_tracking_name(arg, rev);\n+\t\t\tif (remote)\n+\t\t\t\tdie(_(\"don't know whether to create a tracking \"\n+\t\t\t\t      \"branch from remote %s or to checkout path %s, \"\n+\t\t\t\t      \"use -- to disambiguate\"),\n+\t\t\t\t    remote, arg);\n+\t\t\tprintf(\"here?\\n\");\n+\t\t\trecover_with_dwim = 0;\n+\t\t}\n+\n+\t\tif (!has_dash_dash && !no_wildcard(arg))\n \t\t\trecover_with_dwim = 0;\n \t\t/*\n \t\t * Accept \"git checkout foo\" and \"git checkout foo --\"\ndiff --git a/t/t2024-checkout-dwim.sh b/t/t2024-checkout-dwim.sh\nindex 3e5ac81bd2..ea95fb8668 100755\n--- a/t/t2024-checkout-dwim.sh\n+++ b/t/t2024-checkout-dwim.sh\n@@ -215,4 +215,35 @@ test_expect_success 'loosely defined local base branch is reported correctly' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'reject when arg could be part of dwim branch' '\n+\tgit remote add foo file://non-existent-place &&\n+\tgit update-ref refs/remotes/foo/dwim-arg HEAD &&\n+\techo foo >dwim-arg &&\n+\tgit add dwim-arg &&\n+\techo bar >dwim-arg &&\n+\ttest_must_fail git checkout dwim-arg &&\n+\ttest_must_fail git rev-parse refs/heads/dwim-arg -- &&\n+\tgrep bar dwim-arg\n+'\n+\n+test_expect_success 'disambiguate dwim branch and checkout path (1)' '\n+\tgit update-ref refs/remotes/foo/dwim-arg1 HEAD &&\n+\techo foo >dwim-arg1 &&\n+\tgit add dwim-arg1 &&\n+\techo bar >dwim-arg1 &&\n+\tgit checkout -- dwim-arg1 &&\n+\ttest_must_fail git rev-parse refs/heads/dwim-arg1 -- &&\n+\tgrep foo dwim-arg1\n+'\n+\n+test_expect_success 'disambiguate dwim branch and checkout path (2)' '\n+\tgit update-ref refs/remotes/foo/dwim-arg2 HEAD &&\n+\techo foo >dwim-arg2 &&\n+\tgit add dwim-arg2 &&\n+\techo bar >dwim-arg2 &&\n+\tgit checkout dwim-arg2 -- &&\n+\tgit rev-parse refs/heads/dwim-arg2 -- &&\n+\tgrep bar dwim-arg2\n+'\n+\n test_done\n-- 8< --\n"}]}