{"thread":{"id":"27287","subject":"[PATCH] Teach checkout the -n|--dry-run option","startedAt":"2011-05-06T22:12:18Z","lastAt":"2011-05-11T22:47:52Z","messageCount":9,"participants":["Jens Lehmann","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"167293","messageId":"4DC47242.6060205@web.de","threadId":"27287","inReplyTo":null,"subject":"[PATCH] Teach checkout the -n|--dry-run option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2011-05-06T22:12:18Z","receivedAt":"2011-05-06T22:12:18Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"This option can be used to determine if checking out a branch or commit\nwould touch files which are modified in the work tree. It doesn't change\nthe work tree contents or the index, so it can only tell if the checkout\nwould succeed using trivial merges.\n\nIt can neither be used when checking out only certain paths nor together\nwith the '-m' option.\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\nThis is a repost of a RFC patch from Sep 04, 2010 I did not receive any\nresponses upon:\n\nI need this new option for the recursive submodule checkout. Denying a\ncheckout inside a submodule just because it has modifications is a too\nlimiting condition (and it is way too expensive to check the whole tree,\njust looking at those paths going to be changed by the checkout should\nbe much faster, especially for large submodules).\n\nIMO the same behavior that applies for a checkout in the superproject\nshould apply for the checkout inside the submodule: no local changes\nmay be overwritten by the checkout (and the HEAD must match the commit\nrecorded in the superproject, but that is handled elsewhere).\n\nTo be able to test that, I added the -n|--dry-run option to checkout.\nI think I found all relevant places, but a few more eyeballs are highly\nappreciated as I am not very familiar with this part of the code.\n\nA thing I'm not so sure about is the output of show_local_changes(),\nwith -n it doesn't show the changes as they would have been *after* the\n- not executed - checkout but *without* having done it.\nIs that a problem here?\n\n Documentation/git-checkout.txt |   15 ++++++++++++---\n builtin/checkout.c             |   20 +++++++++++++++-----\n t/t2018-checkout-branch.sh     |   23 +++++++++++++++++++++++\n 3 files changed, 50 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-checkout.txt b/Documentation/git-checkout.txt\nindex 1063f69..ae58762 100644\n--- a/Documentation/git-checkout.txt\n+++ b/Documentation/git-checkout.txt\n@@ -8,9 +8,9 @@ git-checkout - Checkout a branch or paths to the working tree\n SYNOPSIS\n --------\n [verse]\n-'git checkout' [-q] [-f] [-m] [<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' [-q] [-f] [-m|-n] [<branch>]\n+'git checkout' [-q] [-f] [-m|-n] [--detach] [<commit>]\n+'git checkout' [-q] [-f] [-m|-n] [[-b|-B|--orphan] <new_branch>] [<start_point>]\n 'git checkout' [-f|--ours|--theirs|-m|--conflict=<style>] [<tree-ish>] [--] <paths>...\n 'git checkout' --patch [<tree-ish>] [--] [<paths>...]\n\n@@ -79,6 +79,13 @@ OPTIONS\n When checking out paths from the index, do not fail upon unmerged\n entries; instead, unmerged entries are ignored.\n\n+-n::\n+--dry-run::\n+\tDon't really checkout the file(s), just check if it would succeed\n+\tusing only trivial merges. Using this option will not touch the work\n+\ttree or the index. The command will fail when the checkout would change\n+\tlocally modified files. This option can not be used together with `-m`.\n+\n --ours::\n --theirs::\n \tWhen checking out paths from the index, check out stage #2\n@@ -167,6 +174,8 @@ should result in deletion of the path).\n +\n When checking out paths from the index, this option lets you recreate\n the conflicted merge in the specified paths.\n++\n+This option does not work together with '-n'.\n\n --conflict=<style>::\n \tThe same as --merge option above, but changes the way the\ndiff --git a/builtin/checkout.c b/builtin/checkout.c\nindex 38632fc..01175d1 100644\n--- a/builtin/checkout.c\n+++ b/builtin/checkout.c\n@@ -33,6 +33,7 @@ struct checkout_opts {\n \tint force_detach;\n \tint writeout_stage;\n \tint writeout_error;\n+\tint dry_run;\n\n \t/* not set by parse_options */\n \tint branch_exists;\n@@ -373,6 +374,8 @@ static int merge_working_tree(struct checkout_opts *opts,\n\n \tresolve_undo_clear();\n \tif (opts->force) {\n+\t\tif (opts->dry_run)\n+\t\t\treturn 0;\n \t\tret = reset_tree(new->commit->tree, opts, 1);\n \t\tif (ret)\n \t\t\treturn ret;\n@@ -397,7 +400,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n\n \t\t/* 2-way merge to the new branch */\n \t\ttopts.initial_checkout = is_cache_unborn();\n-\t\ttopts.update = 1;\n+\t\ttopts.update = !opts->dry_run;\n \t\ttopts.merge = 1;\n \t\ttopts.gently = opts->merge && old->commit;\n \t\ttopts.verbose_update = !opts->quiet;\n@@ -471,8 +474,8 @@ static int merge_working_tree(struct checkout_opts *opts,\n \t\t}\n \t}\n\n-\tif (write_cache(newfd, active_cache, active_nr) ||\n-\t    commit_locked_index(lock_file))\n+\tif (!opts->dry_run && (write_cache(newfd, active_cache, active_nr) ||\n+\t\t\t       commit_locked_index(lock_file)))\n \t\tdie(_(\"unable to write new index file\"));\n\n \tif (!opts->force && !opts->quiet)\n@@ -732,7 +735,7 @@ static int switch_branches(struct checkout_opts *opts, struct branch_info *new)\n \t}\n\n \tret = merge_working_tree(opts, &old, new);\n-\tif (ret)\n+\tif (ret || opts->dry_run)\n \t\treturn ret;\n\n \tif (!opts->quiet && !old.path && old.commit && new->commit != old.commit)\n@@ -941,6 +944,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tOPT_BOOLEAN('m', \"merge\", &opts.merge, \"perform a 3-way merge with the new branch\"),\n \t\tOPT_STRING(0, \"conflict\", &conflict_style, \"style\",\n \t\t\t   \"conflict style (merge or diff3)\"),\n+\t\tOPT_BOOLEAN('n', \"dry-run\", &opts.dry_run, \"show if the checkout would fail because it touches locally modified files\"),\n \t\tOPT_BOOLEAN('p', \"patch\", &patch_mode, \"select hunks interactively\"),\n \t\t{ OPTION_BOOLEAN, 0, \"guess\", &dwim_new_local_branch, NULL,\n \t\t  \"second guess 'git checkout no-such-branch'\",\n@@ -967,7 +971,7 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif (opts.new_branch_force)\n \t\topts.new_branch = opts.new_branch_force;\n\n-\tif (patch_mode && (opts.track > 0 || opts.new_branch\n+\tif (patch_mode && (opts.track > 0 || opts.new_branch || opts.dry_run\n \t\t\t   || opts.new_branch_log || opts.merge || opts.force\n \t\t\t   || opts.force_detach))\n \t\tdie (_(\"--patch is incompatible with all other options\"));\n@@ -1008,6 +1012,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \tif (opts.force && opts.merge)\n \t\tdie(_(\"git checkout: -f and -m are incompatible\"));\n\n+\tif (opts.merge && opts.dry_run)\n+\t\tdie(\"git checkout: -m and -n are incompatible\");\n+\n \t/*\n \t * Extract branch name from command line arguments, so\n \t * all that is left is pathspecs.\n@@ -1060,6 +1067,9 @@ int cmd_checkout(int argc, const char **argv, const char *prefix)\n \t\tif (1 < !!opts.writeout_stage + !!opts.force + !!opts.merge)\n \t\t\tdie(_(\"git checkout: --ours/--theirs, --force and --merge are incompatible when\\nchecking out of the index.\"));\n\n+\t\tif (opts.dry_run)\n+\t\t\tdie(\"git checkout: updating paths is incompatible with -n.\");\n+\n \t\treturn checkout_paths(source_tree, pathspec, &opts);\n \t}\n\ndiff --git a/t/t2018-checkout-branch.sh b/t/t2018-checkout-branch.sh\nindex fa69016..61c82ef 100755\n--- a/t/t2018-checkout-branch.sh\n+++ b/t/t2018-checkout-branch.sh\n@@ -169,4 +169,27 @@ test_expect_success 'checkout -f -B to an existing branch with mergeable changes\n \ttest_must_fail test_dirty_mergeable\n '\n\n+test_expect_success 'checkout -n/--dry-run does not change work tree or index' '\n+\techo precious >expect &&\n+\techo precious >file1 &&\n+\ttest_must_fail git checkout -n branch1 &&\n+\ttest_cmp expect file1 &&\n+\tgit checkout --dry-run -f branch1 &&\n+\ttest_cmp expect file1 &&\n+\ttest_must_fail git checkout -b new_branch --dry-run branch1 &&\n+\ttest_cmp expect file1 &&\n+\tgit checkout -b new_branch -n -f branch1 &&\n+\ttest_cmp expect file1 &&\n+\tgit checkout -f branch1 &&\n+\tgit status -s -uno > actual &&\n+\t! test -s actual &&\n+\tgit checkout -n HEAD^ &&\n+\tgit status -s -uno > actual &&\n+\t! test -s actual\n+'\n+\n+test_expect_success 'checkout -n/--dry-run is not allowed when checking out only certain paths' '\n+\ttest_must_fail git checkout -n branch1 file1 &&\n+\ttest_must_fail git checkout -n HEAD file1\n+'\n test_done\n-- \n1.7.5.1.174.g799a9\n"},{"id":"167299","messageId":"7vhb97xx5g.fsf@alter.siamese.dyndns.org","threadId":"27287","inReplyTo":"4DC47242.6060205@web.de","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-05-06T22:49:15Z","receivedAt":"2011-05-06T22:49:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> This option can be used to determine if checking out a branch or commit\n> would touch files which are modified in the work tree. It doesn't change\n> the work tree contents or the index, so it can only tell if the checkout\n> would succeed using trivial merges.\n\nI hated this patch when I saw it the first time.  I thought you were\njoking and let it pass. But now you brought it again, I hate it even more\nnow.\n\nI do not see a merit in contaminating the checkout Porcelain with a half\nbaked [*1*] \"dry-run\" code, when your ultimate motive to use it in\nsubmodule script and exercise only a small portion of checkout codepaths.\nYou are only interested in branch switching, and not other things the\nPorcelain can do, like checking out a path out of the index or a tree, or\nre-checking out a conflicted path out of the index.\n\nIn other words, can't the check you need in submodule be scripted around\nthe specific plumbing responsible for the branch switching, which is:\n\n    $ git read-tree -m HEAD $other_branch\n\n> @@ -397,7 +400,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n>\n>  \t\t/* 2-way merge to the new branch */\n>  \t\ttopts.initial_checkout = is_cache_unborn();\n> -\t\ttopts.update = 1;\n> +\t\ttopts.update = !opts->dry_run;\n>  \t\ttopts.merge = 1;\n>  \t\ttopts.gently = opts->merge && old->commit;\n>  \t\ttopts.verbose_update = !opts->quiet;\n\nWhat you are doing in this part of your patch is exactly that two-tree\nform of the \"read-tree -m\", no?\n\n\n[Footnote]\n\n*1* Look at how many places you say \"are incompatible\" when you really\nmean \"I didn't bother to think deeply enough about implementing this\ncombination\".\n"},{"id":"167334","messageId":"7vfwoqwby5.fsf@alter.siamese.dyndns.org","threadId":"27287","inReplyTo":"7vhb97xx5g.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-05-07T19:24:50Z","receivedAt":"2011-05-07T19:24:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> In other words, can't the check you need in submodule be scripted around\n> the specific plumbing responsible for the branch switching, which is:\n>\n>     $ git read-tree -m HEAD $other_branch\n>\n>> @@ -397,7 +400,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n>>\n>>  \t\t/* 2-way merge to the new branch */\n>>  \t\ttopts.initial_checkout = is_cache_unborn();\n>> -\t\ttopts.update = 1;\n>> +\t\ttopts.update = !opts->dry_run;\n>>  \t\ttopts.merge = 1;\n>>  \t\ttopts.gently = opts->merge && old->commit;\n>>  \t\ttopts.verbose_update = !opts->quiet;\n>\n> What you are doing in this part of your patch is exactly that two-tree\n> form of the \"read-tree -m\", no?\n\nThat is, this would succeed:\n\n\t$ git reset --hard master\n        $ git read-tree --index-output=rubbish -m master next\n        \nand these would fail:\n\n\t$ git reset --hard master\n\t$ echo >>Makefile\n        $ git read-tree --index-output=rubbish -m master next\n        error: Entry 'Makefile' not uptodate. Cannot merge.\n\n\t$ git reset --hard master\n\t$ echo >>Makefile\n\t$ git add Makefile\n        $ git read-tree --index-output=rubbish -m master next\n        error: Entry 'Makefile' would be overwritten by merge. Cannot merge.\n\nHaving said that, please do not discard your patch.  After sleeping on\nthis, I started to think that \"checkout -n\" might be a better interface\nthan using the plumbing read-tree in the longer term, especially if you\ncan enhance it to handle \"checkout -m -n\" to check if the local change can\nbe merged without conflicts.\n\nBut if the only question you are interested in is \"can I switch to that\nbranch from the current state of the index and the working tree?\", I would\nprefer to see if the script can use \"read-tree -m\" approach first.\n\nWe may also want to add \"read-tree -n\" so that you do not have to specify\na dummy index output only to prevent from writing the real index over,\nthough.\n"},{"id":"167363","messageId":"4DC67CF4.80901@web.de","threadId":"27287","inReplyTo":"7vfwoqwby5.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2011-05-08T11:22:28Z","receivedAt":"2011-05-08T11:22:28Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 07.05.2011 21:24, schrieb Junio C Hamano:\n> Junio C Hamano <gitster@pobox.com> writes:\n> \n>> In other words, can't the check you need in submodule be scripted around\n>> the specific plumbing responsible for the branch switching, which is:\n>>\n>>     $ git read-tree -m HEAD $other_branch\n>>\n>>> @@ -397,7 +400,7 @@ static int merge_working_tree(struct checkout_opts *opts,\n>>>\n>>>  \t\t/* 2-way merge to the new branch */\n>>>  \t\ttopts.initial_checkout = is_cache_unborn();\n>>> -\t\ttopts.update = 1;\n>>> +\t\ttopts.update = !opts->dry_run;\n>>>  \t\ttopts.merge = 1;\n>>>  \t\ttopts.gently = opts->merge && old->commit;\n>>>  \t\ttopts.verbose_update = !opts->quiet;\n>>\n>> What you are doing in this part of your patch is exactly that two-tree\n>> form of the \"read-tree -m\", no?\n> \n> That is, this would succeed:\n> \n> \t$ git reset --hard master\n>         $ git read-tree --index-output=rubbish -m master next\n>         \n> and these would fail:\n> \n> \t$ git reset --hard master\n> \t$ echo >>Makefile\n>         $ git read-tree --index-output=rubbish -m master next\n>         error: Entry 'Makefile' not uptodate. Cannot merge.\n> \n> \t$ git reset --hard master\n> \t$ echo >>Makefile\n> \t$ git add Makefile\n>         $ git read-tree --index-output=rubbish -m master next\n>         error: Entry 'Makefile' would be overwritten by merge. Cannot merge.\n\nThanks for pointing me to \"git read-tree -m\". When I saw that a \"git\ncheckout -n\" would do exactly what I needed, I stopped looking for\nalternatives (especially as I saw that adding -n there would help\nother non-submodule use cases as well).\n\n> Having said that, please do not discard your patch.  After sleeping on\n> this, I started to think that \"checkout -n\" might be a better interface\n> than using the plumbing read-tree in the longer term, especially if you\n> can enhance it to handle \"checkout -m -n\" to check if the local change can\n> be merged without conflicts.\n\nI'll see if I can come up with a solution for the \"-m -n\" case (I stopped\nafter implementing the checkout branch case I needed to get some feedback\nif this thing went into the right direction). And I assume the \"git\ncheckout <pathspec>\" case should learn -n too?\n\n> But if the only question you are interested in is \"can I switch to that\n> branch from the current state of the index and the working tree?\", I would\n> prefer to see if the script can use \"read-tree -m\" approach first.\n\nYup, I will try that.\n\n> We may also want to add \"read-tree -n\" so that you do not have to specify\n> a dummy index output only to prevent from writing the real index over,\n> though.\n\nHmm, wouldn't using \"read-tree --index-output=/dev/null\" be equivalent to\n\"read-tree -n\"? But nonetheless it might make sense to add the -n option.\n"},{"id":"167449","messageId":"4DC70200.1080201@web.de","threadId":"27287","inReplyTo":"4DC67CF4.80901@web.de","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2011-05-08T20:50:08Z","receivedAt":"2011-05-08T20:50:08Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 08.05.2011 13:22, schrieb Jens Lehmann:\n> Am 07.05.2011 21:24, schrieb Junio C Hamano:\n>> We may also want to add \"read-tree -n\" so that you do not have to specify\n>> a dummy index output only to prevent from writing the real index over,\n>> though.\n> \n> Hmm, wouldn't using \"read-tree --index-output=/dev/null\" be equivalent to\n> \"read-tree -n\"? But nonetheless it might make sense to add the -n option.\n\nNo idea how I could manage to test \"read-tree --index-output=/dev/null\"\nsuccessfully without getting an \"unable to write new index file\" error.\n\nBut using read-tree works for me, so what about something like this,\nmaybe with some more tests?\n\n-------------8<---------------\nSubject: [PATCH] Teach read-tree the -n|--dry-run option\n\nUsing this option tells read-tree to not update the index. That makes it\npossible to check if updating the index would be successful without\nchanging it.\n\nAs using --dry-run is expected to have no side effects, this option makes\nno sense together with \"-u\".\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n Documentation/git-read-tree.txt |    5 +++++\n builtin/read-tree.c             |    7 +++++--\n t/t1000-read-tree-m-3way.sh     |    2 ++\n 3 files changed, 12 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex 26fdadc..a35849f 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -53,6 +53,11 @@ OPTIONS\n \ttrees that are not directly related to the current\n \tworking tree status into a temporary index file.\n\n+-n::\n+--dry-run::\n+\tDon't write the index file. This option isn't allowed together\n+\twith -u.\n+\n -v::\n \tShow the progress of checking files out.\n\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 93c9281..693576f 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -98,7 +98,7 @@ static struct lock_file lock_file;\n\n int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n {\n-\tint i, newfd, stage = 0;\n+\tint i, newfd, stage = 0, dry_run = 0;\n \tunsigned char sha1[20];\n \tstruct tree_desc t[MAX_UNPACK_TREES];\n \tstruct unpack_trees_options opts;\n@@ -130,6 +130,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t  PARSE_OPT_NONEG, exclude_per_directory_cb },\n \t\tOPT_SET_INT('i', NULL, &opts.index_only,\n \t\t\t    \"don't check the working tree after merging\", 1),\n+\t\tOPT__DRY_RUN(&dry_run, \"don't update the index\"),\n \t\tOPT_SET_INT(0, \"no-sparse-checkout\", &opts.skip_sparse_checkout,\n \t\t\t    \"skip applying sparse checkout filter\", 1),\n \t\tOPT_SET_INT(0, \"debug-unpack\", &opts.debug_unpack,\n@@ -183,6 +184,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\tdie(\"--exclude-per-directory is meaningless unless -u\");\n \tif (opts.merge && !opts.index_only)\n \t\tsetup_work_tree();\n+\tif (opts.update && dry_run)\n+\t\tdie(\"--dry-run contradicts -u\");\n\n \tif (opts.merge) {\n \t\tif (stage < 2)\n@@ -219,7 +222,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \tif (unpack_trees(nr_trees, t, &opts))\n \t\treturn 128;\n\n-\tif (opts.debug_unpack)\n+\tif (opts.debug_unpack || dry_run)\n \t\treturn 0; /* do not write the index out */\n\n \t/*\ndiff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh\nindex ca8a409..bcfb5e6 100755\n--- a/t/t1000-read-tree-m-3way.sh\n+++ b/t/t1000-read-tree-m-3way.sh\n@@ -259,6 +259,8 @@ test_expect_success \\\n     \"rm -f .git/index AA &&\n      cp .orig-A/AA AA &&\n      git update-index --add AA &&\n+     git read-tree -n -m $tree_O $tree_A $tree_B &&\n+     test_must_fail check_result &&\n      git read-tree -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n-- \n1.7.5.1.218.g8af57\n"},{"id":"167450","messageId":"7vwri0ric1.fsf@alter.siamese.dyndns.org","threadId":"27287","inReplyTo":"4DC70200.1080201@web.de","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-05-08T21:30:22Z","receivedAt":"2011-05-08T21:30:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh\n> index ca8a409..bcfb5e6 100755\n> --- a/t/t1000-read-tree-m-3way.sh\n> +++ b/t/t1000-read-tree-m-3way.sh\n> @@ -259,6 +259,8 @@ test_expect_success \\\n>      \"rm -f .git/index AA &&\n>       cp .orig-A/AA AA &&\n>       git update-index --add AA &&\n> +     git read-tree -n -m $tree_O $tree_A $tree_B &&\n> +     test_must_fail check_result &&\n\nThat's a rather sloppy way to test that the command did not do anything to\ncompare one possible outcome, instead of verifying that the result is\nidentical to the original condition, no?\n\nHow about\n\n\t...\n\tgit update_index --add AA &&\n        git ls-files -s >pre-dry-run &&\n        git read-tree -n -m $tree_O $tree_A $tree_B &&\n        git ls-files -s >post-dry-run &&\n        test_cmp pre-dry-run post-dry-run &&\n        ...\n\nWe also should be checking that the command reports it is going to fail\nwhen it should as well.  Always remember to check both sides of the coin.\n\n>       git read-tree -m $tree_O $tree_A $tree_B &&\n>       check_result\"\n\nI suspect that it would make sense to replace\n\n\tgit read-tree $args && check_result\n\nwith\n        \n\tread_tree_must_succeed $args\n\nand\n\n\ttest_must_fail git read-tree $args\n\nwith\n\n\tread_tree_must_fail $args\n\nand implement two shell wrappers, perhaps like this.\n\nread_tree_must_succeed () {\n\tgit ls-files -s >pre-dry-run &&\n\tgit read-tree -n \"$@\" &&\n        git ls-files -s >post-dry-run &&\n        test_cmp pre-dry-run post-dry-run &&\n        git read-tree \"$@\"\n}\n\nread_tree_must_fail () {\n\tgit ls-files -s >pre-dry-run &&\n\ttest_must_fail git read-tree -n \"$@\" &&\n        git ls-files -s >post-dry-run &&\n\ttest_must_fail git read-tree \"$@\"\n}\n"},{"id":"167454","messageId":"4DC70E1A.6060702@web.de","threadId":"27287","inReplyTo":"7vwri0ric1.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH] Teach checkout the -n|--dry-run option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2011-05-08T21:41:46Z","receivedAt":"2011-05-08T21:41:46Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Am 08.05.2011 23:30, schrieb Junio C Hamano:\n> Jens Lehmann <Jens.Lehmann@web.de> writes:\n> \n>> diff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh\n>> index ca8a409..bcfb5e6 100755\n>> --- a/t/t1000-read-tree-m-3way.sh\n>> +++ b/t/t1000-read-tree-m-3way.sh\n>> @@ -259,6 +259,8 @@ test_expect_success \\\n>>      \"rm -f .git/index AA &&\n>>       cp .orig-A/AA AA &&\n>>       git update-index --add AA &&\n>> +     git read-tree -n -m $tree_O $tree_A $tree_B &&\n>> +     test_must_fail check_result &&\n> \n> That's a rather sloppy way to test that the command did not do anything to\n> compare one possible outcome, instead of verifying that the result is\n> identical to the original condition, no?\n> \n> How about\n> \n> \t...\n> \tgit update_index --add AA &&\n>         git ls-files -s >pre-dry-run &&\n>         git read-tree -n -m $tree_O $tree_A $tree_B &&\n>         git ls-files -s >post-dry-run &&\n>         test_cmp pre-dry-run post-dry-run &&\n>         ...\n\nYeah, that is much better than my first sketch.\n\n> We also should be checking that the command reports it is going to fail\n> when it should as well.  Always remember to check both sides of the coin.\n> \n>>       git read-tree -m $tree_O $tree_A $tree_B &&\n>>       check_result\"\n> \n> I suspect that it would make sense to replace\n> \n> \tgit read-tree $args && check_result\n> \n> with\n>         \n> \tread_tree_must_succeed $args\n> \n> and\n> \n> \ttest_must_fail git read-tree $args\n> \n> with\n> \n> \tread_tree_must_fail $args\n> \n> and implement two shell wrappers, perhaps like this.\n> \n> read_tree_must_succeed () {\n> \tgit ls-files -s >pre-dry-run &&\n> \tgit read-tree -n \"$@\" &&\n>         git ls-files -s >post-dry-run &&\n>         test_cmp pre-dry-run post-dry-run &&\n>         git read-tree \"$@\"\n> }\n> \n> read_tree_must_fail () {\n> \tgit ls-files -s >pre-dry-run &&\n> \ttest_must_fail git read-tree -n \"$@\" &&\n>         git ls-files -s >post-dry-run &&\n> \ttest_must_fail git read-tree \"$@\"\n> }\n\nThanks, will send an updated patch with better test cases soon ...\n"},{"id":"167693","messageId":"4DCB04A1.3010202@web.de","threadId":"27287","inReplyTo":"7vwri0ric1.fsf@alter.siamese.dyndns.org","subject":"[PATCH] Teach read-tree the -n|--dry-run option","fromName":"Jens Lehmann","fromEmail":"jens.lehmann@web.de","sentAt":"2011-05-11T21:50:25Z","receivedAt":"2011-05-11T21:50:25Z","isPatch":true,"sender":{"key":"jens.lehmann@web.de","avatar":"https://avatars.githubusercontent.com/u/135220?v=4"},"body":"Using this option tells read-tree to not update the index. That makes it\npossible to check if updating the index would be successful without\nchanging it.\n\nAs using --dry-run is expected to have no side effects, this option makes\nno sense together with \"-u\".\n\nSigned-off-by: Jens Lehmann <Jens.Lehmann@web.de>\n---\n\nNow with updated tests.\n\n Documentation/git-read-tree.txt |    5 ++\n builtin/read-tree.c             |    7 ++-\n t/t1000-read-tree-m-3way.sh     |   96 +++++++++++++++++++++++----------------\n t/t1001-read-tree-m-2way.sh     |   48 +++++++++++--------\n t/t1002-read-tree-m-u-2way.sh   |    4 ++\n 5 files changed, 98 insertions(+), 62 deletions(-)\n\ndiff --git a/Documentation/git-read-tree.txt b/Documentation/git-read-tree.txt\nindex 26fdadc..a35849f 100644\n--- a/Documentation/git-read-tree.txt\n+++ b/Documentation/git-read-tree.txt\n@@ -53,6 +53,11 @@ OPTIONS\n \ttrees that are not directly related to the current\n \tworking tree status into a temporary index file.\n\n+-n::\n+--dry-run::\n+\tDon't write the index file. This option isn't allowed together\n+\twith -u.\n+\n -v::\n \tShow the progress of checking files out.\n\ndiff --git a/builtin/read-tree.c b/builtin/read-tree.c\nindex 93c9281..693576f 100644\n--- a/builtin/read-tree.c\n+++ b/builtin/read-tree.c\n@@ -98,7 +98,7 @@ static struct lock_file lock_file;\n\n int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n {\n-\tint i, newfd, stage = 0;\n+\tint i, newfd, stage = 0, dry_run = 0;\n \tunsigned char sha1[20];\n \tstruct tree_desc t[MAX_UNPACK_TREES];\n \tstruct unpack_trees_options opts;\n@@ -130,6 +130,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\t  PARSE_OPT_NONEG, exclude_per_directory_cb },\n \t\tOPT_SET_INT('i', NULL, &opts.index_only,\n \t\t\t    \"don't check the working tree after merging\", 1),\n+\t\tOPT__DRY_RUN(&dry_run, \"don't update the index\"),\n \t\tOPT_SET_INT(0, \"no-sparse-checkout\", &opts.skip_sparse_checkout,\n \t\t\t    \"skip applying sparse checkout filter\", 1),\n \t\tOPT_SET_INT(0, \"debug-unpack\", &opts.debug_unpack,\n@@ -183,6 +184,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \t\tdie(\"--exclude-per-directory is meaningless unless -u\");\n \tif (opts.merge && !opts.index_only)\n \t\tsetup_work_tree();\n+\tif (opts.update && dry_run)\n+\t\tdie(\"--dry-run contradicts -u\");\n\n \tif (opts.merge) {\n \t\tif (stage < 2)\n@@ -219,7 +222,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)\n \tif (unpack_trees(nr_trees, t, &opts))\n \t\treturn 128;\n\n-\tif (opts.debug_unpack)\n+\tif (opts.debug_unpack || dry_run)\n \t\treturn 0; /* do not write the index out */\n\n \t/*\ndiff --git a/t/t1000-read-tree-m-3way.sh b/t/t1000-read-tree-m-3way.sh\nindex ca8a409..a386cfd 100755\n--- a/t/t1000-read-tree-m-3way.sh\n+++ b/t/t1000-read-tree-m-3way.sh\n@@ -131,13 +131,29 @@ check_result () {\n     test_cmp expected current\n }\n\n+read_tree_must_succeed () {\n+    git ls-files -s >pre-dry-run &&\n+    git read-tree -n \"$@\" &&\n+    git ls-files -s >post-dry-run &&\n+    test_cmp pre-dry-run post-dry-run &&\n+    git read-tree \"$@\"\n+}\n+\n+read_tree_must_fail () {\n+    git ls-files -s >pre-dry-run &&\n+    test_must_fail git read-tree -n \"$@\" &&\n+    git ls-files -s >post-dry-run &&\n+    test_cmp pre-dry-run post-dry-run &&\n+    test_must_fail git read-tree \"$@\"\n+}\n+\n # This is done on an empty work directory, which is the normal\n # merge person behaviour.\n test_expect_success \\\n     '3-way merge with git read-tree -m, empty cache' \\\n     \"rm -fr [NDMALTS][NDMALTSF] Z &&\n      rm .git/index &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n # This starts out with the first head, which is the normal\n@@ -146,9 +162,9 @@ test_expect_success \\\n     '3-way merge with git read-tree -m, match H' \\\n     \"rm -fr [NDMALTS][NDMALTSF] Z &&\n      rm .git/index &&\n-     git read-tree $tree_A &&\n+     read_tree_must_succeed $tree_A &&\n      git checkout-index -f -u -a &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n : <<\\END_OF_CASE_TABLE\n@@ -211,7 +227,7 @@ test_expect_success '1 - must not have an entry not in A.' \"\n      rm -f .git/index XX &&\n      echo XX >XX &&\n      git update-index --add XX &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -219,7 +235,7 @@ test_expect_success \\\n     \"rm -f .git/index NA &&\n      cp .orig-B/NA NA &&\n      git update-index --add NA &&\n-     git read-tree -m $tree_O $tree_A $tree_B\"\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B\"\n\n test_expect_success \\\n     '2 - matching B alone is OK in !O && !A && B case.' \\\n@@ -227,14 +243,14 @@ test_expect_success \\\n      cp .orig-B/NA NA &&\n      git update-index --add NA &&\n      echo extra >>NA &&\n-     git read-tree -m $tree_O $tree_A $tree_B\"\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B\"\n\n test_expect_success \\\n     '3 - must match A in !O && A && !B case.' \\\n     \"rm -f .git/index AN &&\n      cp .orig-A/AN AN &&\n      git update-index --add AN &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -243,7 +259,7 @@ test_expect_success \\\n      cp .orig-A/AN AN &&\n      git update-index --add AN &&\n      echo extra >>AN &&\n-     git read-tree -m $tree_O $tree_A $tree_B\"\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B\"\n\n test_expect_success \\\n     '3 (fail) - must match A in !O && A && !B case.' \"\n@@ -251,7 +267,7 @@ test_expect_success \\\n      cp .orig-A/AN AN &&\n      echo extra >>AN &&\n      git update-index --add AN &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -259,7 +275,7 @@ test_expect_success \\\n     \"rm -f .git/index AA &&\n      cp .orig-A/AA AA &&\n      git update-index --add AA &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -268,7 +284,7 @@ test_expect_success \\\n      cp .orig-A/AA AA &&\n      git update-index --add AA &&\n      echo extra >>AA &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -277,7 +293,7 @@ test_expect_success \\\n      cp .orig-A/AA AA &&\n      echo extra >>AA &&\n      git update-index --add AA &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -285,7 +301,7 @@ test_expect_success \\\n     \"rm -f .git/index LL &&\n      cp .orig-A/LL LL &&\n      git update-index --add LL &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -294,7 +310,7 @@ test_expect_success \\\n      cp .orig-A/LL LL &&\n      git update-index --add LL &&\n      echo extra >>LL &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -303,7 +319,7 @@ test_expect_success \\\n      cp .orig-A/LL LL &&\n      echo extra >>LL &&\n      git update-index --add LL &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -311,7 +327,7 @@ test_expect_success \\\n      rm -f .git/index DD &&\n      echo DD >DD &&\n      git update-index --add DD &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -319,7 +335,7 @@ test_expect_success \\\n      rm -f .git/index DM &&\n      cp .orig-B/DM DM &&\n      git update-index --add DM &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -327,7 +343,7 @@ test_expect_success \\\n      rm -f .git/index DN &&\n      cp .orig-B/DN DN &&\n      git update-index --add DN &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -335,7 +351,7 @@ test_expect_success \\\n     \"rm -f .git/index MD &&\n      cp .orig-A/MD MD &&\n      git update-index --add MD &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -344,7 +360,7 @@ test_expect_success \\\n      cp .orig-A/MD MD &&\n      git update-index --add MD &&\n      echo extra >>MD &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -353,7 +369,7 @@ test_expect_success \\\n      cp .orig-A/MD MD &&\n      echo extra >>MD &&\n      git update-index --add MD &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -361,7 +377,7 @@ test_expect_success \\\n     \"rm -f .git/index ND &&\n      cp .orig-A/ND ND &&\n      git update-index --add ND &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -370,7 +386,7 @@ test_expect_success \\\n      cp .orig-A/ND ND &&\n      git update-index --add ND &&\n      echo extra >>ND &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -379,7 +395,7 @@ test_expect_success \\\n      cp .orig-A/ND ND &&\n      echo extra >>ND &&\n      git update-index --add ND &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -387,7 +403,7 @@ test_expect_success \\\n     \"rm -f .git/index MM &&\n      cp .orig-A/MM MM &&\n      git update-index --add MM &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -396,7 +412,7 @@ test_expect_success \\\n      cp .orig-A/MM MM &&\n      git update-index --add MM &&\n      echo extra >>MM &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -405,7 +421,7 @@ test_expect_success \\\n      cp .orig-A/MM MM &&\n      echo extra >>MM &&\n      git update-index --add MM &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -413,7 +429,7 @@ test_expect_success \\\n     \"rm -f .git/index SS &&\n      cp .orig-A/SS SS &&\n      git update-index --add SS &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -422,7 +438,7 @@ test_expect_success \\\n      cp .orig-A/SS SS &&\n      git update-index --add SS &&\n      echo extra >>SS &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -431,7 +447,7 @@ test_expect_success \\\n      cp .orig-A/SS SS &&\n      echo extra >>SS &&\n      git update-index --add SS &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -439,7 +455,7 @@ test_expect_success \\\n     \"rm -f .git/index MN &&\n      cp .orig-A/MN MN &&\n      git update-index --add MN &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -448,7 +464,7 @@ test_expect_success \\\n      cp .orig-A/MN MN &&\n      git update-index --add MN &&\n      echo extra >>MN &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -456,7 +472,7 @@ test_expect_success \\\n     \"rm -f .git/index NM &&\n      cp .orig-A/NM NM &&\n      git update-index --add NM &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -465,7 +481,7 @@ test_expect_success \\\n      cp .orig-B/NM NM &&\n      git update-index --add NM &&\n      echo extra >>NM &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -474,7 +490,7 @@ test_expect_success \\\n      cp .orig-A/NM NM &&\n      git update-index --add NM &&\n      echo extra >>NM &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -483,7 +499,7 @@ test_expect_success \\\n      cp .orig-A/NM NM &&\n      echo extra >>NM &&\n      git update-index --add NM &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n test_expect_success \\\n@@ -491,7 +507,7 @@ test_expect_success \\\n     \"rm -f .git/index NN &&\n      cp .orig-A/NN NN &&\n      git update-index --add NN &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -500,7 +516,7 @@ test_expect_success \\\n      cp .orig-A/NN NN &&\n      git update-index --add NN &&\n      echo extra >>NN &&\n-     git read-tree -m $tree_O $tree_A $tree_B &&\n+     read_tree_must_succeed -m $tree_O $tree_A $tree_B &&\n      check_result\"\n\n test_expect_success \\\n@@ -509,7 +525,7 @@ test_expect_success \\\n      cp .orig-A/NN NN &&\n      echo extra >>NN &&\n      git update-index --add NN &&\n-     test_must_fail git read-tree -m $tree_O $tree_A $tree_B\n+     read_tree_must_fail -m $tree_O $tree_A $tree_B\n \"\n\n # #16\n@@ -522,7 +538,7 @@ test_expect_success \\\n     echo E16 >F16 &&\n     git update-index F16 &&\n     tree1=`git write-tree` &&\n-    git read-tree -m $tree0 $tree1 $tree1 $tree0 &&\n+    read_tree_must_succeed -m $tree0 $tree1 $tree1 $tree0 &&\n     git ls-files --stage'\n\n test_done\ndiff --git a/t/t1001-read-tree-m-2way.sh b/t/t1001-read-tree-m-2way.sh\nindex 680d992..ebe7c4d 100755\n--- a/t/t1001-read-tree-m-2way.sh\n+++ b/t/t1001-read-tree-m-2way.sh\n@@ -48,6 +48,14 @@ check_cache_at () {\n \tesac\n }\n\n+read_tree_must_succeed () {\n+    git ls-files -s >pre-dry-run &&\n+    git read-tree -n \"$@\" &&\n+    git ls-files -s >post-dry-run &&\n+    test_cmp pre-dry-run post-dry-run &&\n+    git read-tree \"$@\"\n+}\n+\n cat >bozbar-old <<\\EOF\n This is a sample file used in two-way fast-forward merge\n tests.  Its second line ends with a magic word bozbar\n@@ -94,7 +102,7 @@ echo '+100644 X 0\tyomin' >expected\n test_expect_success \\\n     '4 - carry forward local addition.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      git update-index --add yomin &&\n      read_tree_twoway $treeH $treeM &&\n@@ -106,7 +114,7 @@ test_expect_success \\\n test_expect_success \\\n     '5 - carry forward local addition.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo yomin >yomin &&\n      git update-index --add yomin &&\n@@ -120,7 +128,7 @@ test_expect_success \\\n test_expect_success \\\n     '6 - local addition already has the same.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      git update-index --add frotz &&\n      read_tree_twoway $treeH $treeM &&\n@@ -131,7 +139,7 @@ test_expect_success \\\n test_expect_success \\\n     '7 - local addition already has the same.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo frotz >frotz &&\n      git update-index --add frotz &&\n@@ -144,7 +152,7 @@ test_expect_success \\\n test_expect_success \\\n     '8 - conflicting addition.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo frotz frotz >frotz &&\n      git update-index --add frotz &&\n@@ -153,7 +161,7 @@ test_expect_success \\\n test_expect_success \\\n     '9 - conflicting addition.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo frotz frotz >frotz &&\n      git update-index --add frotz &&\n@@ -163,7 +171,7 @@ test_expect_success \\\n test_expect_success \\\n     '10 - path removed.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo rezrov >rezrov &&\n      git update-index --add rezrov &&\n@@ -174,7 +182,7 @@ test_expect_success \\\n test_expect_success \\\n     '11 - dirty path removed.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo rezrov >rezrov &&\n      git update-index --add rezrov &&\n@@ -184,7 +192,7 @@ test_expect_success \\\n test_expect_success \\\n     '12 - unmatching local changes being removed.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo rezrov rezrov >rezrov &&\n      git update-index --add rezrov &&\n@@ -193,7 +201,7 @@ test_expect_success \\\n test_expect_success \\\n     '13 - unmatching local changes being removed.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo rezrov rezrov >rezrov &&\n      git update-index --add rezrov &&\n@@ -208,7 +216,7 @@ EOF\n test_expect_success \\\n     '14 - unchanged in two heads.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo nitfol nitfol >nitfol &&\n      git update-index --add nitfol &&\n@@ -221,7 +229,7 @@ test_expect_success \\\n test_expect_success \\\n     '15 - unchanged in two heads.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo nitfol nitfol >nitfol &&\n      git update-index --add nitfol &&\n@@ -235,7 +243,7 @@ test_expect_success \\\n test_expect_success \\\n     '16 - conflicting local change.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo bozbar bozbar >bozbar &&\n      git update-index --add bozbar &&\n@@ -244,7 +252,7 @@ test_expect_success \\\n test_expect_success \\\n     '17 - conflicting local change.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      echo bozbar bozbar >bozbar &&\n      git update-index --add bozbar &&\n@@ -254,7 +262,7 @@ test_expect_success \\\n test_expect_success \\\n     '18 - local change already having a good result.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      cat bozbar-new >bozbar &&\n      git update-index --add bozbar &&\n@@ -266,7 +274,7 @@ test_expect_success \\\n test_expect_success \\\n     '19 - local change already having a good result, further modified.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      cat bozbar-new >bozbar &&\n      git update-index --add bozbar &&\n@@ -279,7 +287,7 @@ test_expect_success \\\n test_expect_success \\\n     '20 - no local change, use new tree.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      cat bozbar-old >bozbar &&\n      git update-index --add bozbar &&\n@@ -291,7 +299,7 @@ test_expect_success \\\n test_expect_success \\\n     '21 - no local change, dirty cache.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      cat bozbar-old >bozbar &&\n      git update-index --add bozbar &&\n@@ -302,7 +310,7 @@ test_expect_success \\\n test_expect_success \\\n     '22 - local change cache updated.' \\\n     'rm -f .git/index &&\n-     git read-tree $treeH &&\n+     read_tree_must_succeed $treeH &&\n      git checkout-index -u -f -q -a &&\n      sed -e \"s/such as/SUCH AS/\" bozbar-old >bozbar &&\n      git update-index --add bozbar &&\n@@ -401,7 +409,7 @@ test_expect_success '-m references the correct modified tree' '\n \techo a >file-a &&\n \tgit add file-a &&\n \tgit ls-tree $(git write-tree) file-a >expect &&\n-\tgit read-tree -m HEAD initial-mod &&\n+\tread_tree_must_succeed -m HEAD initial-mod &&\n \tgit ls-tree $(git write-tree) file-a >actual &&\n \ttest_cmp expect actual\n '\ndiff --git a/t/t1002-read-tree-m-u-2way.sh b/t/t1002-read-tree-m-u-2way.sh\nindex a4a17e0..ad9a4e8 100755\n--- a/t/t1002-read-tree-m-u-2way.sh\n+++ b/t/t1002-read-tree-m-u-2way.sh\n@@ -341,4 +341,8 @@ test_expect_success \\\n      test_cmp DFDF.out DFDFcheck.out &&\n      check_cache_at DF/DF clean'\n\n+test_expect_success \\\n+    '-u is not allowed with -n' \\\n+    'test_must_fail git read-tree -n -u -m $treeDF $treeDFDF'\n+\n test_done\n-- \n1.7.5.1.218.g2da34\n"},{"id":"167695","messageId":"7v8vucg8h3.fsf@alter.siamese.dyndns.org","threadId":"27287","inReplyTo":"4DCB04A1.3010202@web.de","subject":"Re: [PATCH] Teach read-tree the -n|--dry-run option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-05-11T22:47:52Z","receivedAt":"2011-05-11T22:47:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jens Lehmann <Jens.Lehmann@web.de> writes:\n\n> Using this option tells read-tree to not update the index. That makes it\n> possible to check if updating the index would be successful without\n> changing it.\n\nThanks for verifying the 3-way case as well.\n\n> As using --dry-run is expected to have no side effects, this option makes\n> no sense together with \"-u\".\n\nI wondered if there be cases where \"read-tree -m <1 to 3 trees>\" will\nsucceed but the same command with \"-u\" can fail. If there were such cases,\nwe would need more than this patch does.\n\nAn obvious case is when you cannot write to your working tree, perhaps due\nto ENOSPC or incorrect permission settings in the working tree, but I am\nnot worried about that. I am only worried about situations related to\nversion control (i.e. you may lose local changes).\n\nI _think_ the only difference \"-u\" makes is that check_updates() makes\ncalls to checkout_entry(), and the only errors checkout_entry() would\ncatch are filesystem related ones. Even though there is one conditional\nthat says \"if the cached stat does not match, you cannot checkout unless\nyou set .force to the checkout state\", but unpack_trees() does set that\nflag, so we should be safe.\n\nThanks.\n"}]}