{"thread":{"id":"58026","subject":"[PATCH v3 0/6] remote: handle negative refspecs with show","startedAt":"2022-06-17T00:20:43Z","lastAt":"2022-06-17T00:20:56Z","messageCount":7,"participants":["Jacob Keller"],"isPatch":true,"patchVersion":3,"patchTotal":6},"messages":[{"id":"457439","messageId":"20220617002036.1577-1-jacob.keller@gmail.com","threadId":"58026","inReplyTo":null,"subject":"[PATCH v3 0/6] remote: handle negative refspecs with show","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:30Z","receivedAt":"2022-06-17T00:20:43Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"The git remote show command does not handle negative refspecs. In fact, the\nfunction will happily show that the refs will be fetched, even though they\nwon't be.\n\nThe first patch in this series fixes the show issue for new refs that should\nbe marked as skipped. The later patches do some cleanup on the\nt5505-remote.sh script, improving the test file, along with some improved\ntest infrastructure.\n\nFinally, I also noticed that git remote prune doesn't interact as expected\nwith negative refspecs either, so there is a patch to add an expected\nfailure for this as well.\n\nI suspect we need to dig into get_stale_heads and make that handle negative\nrefspecs properly, but I wasn't able to figure that out in the time I have\ntoday.\n\nChanges since v2:\n* re-ordered so that the fix is first\n* cleaned up helper functions to honor -C instead of hard coding 'test'\n* added expected failures for the short comings of this fix\n\nJacob Keller (6):\n  remote: handle negative refspecs in git remote show\n  t5505: remove sub shell use in favor of git -C\n  tests: handle --global directly in test_config/test_unconfig\n  tests: only automatically unset matching values from test_config\n  t5505: use test_config where appropriate\n  remote: add test for negative refspec with prune\n\n builtin/remote.c                        |   12 +-\n remote.c                                |    2 +-\n remote.h                                |    6 +\n t/lib-parallel-checkout.sh              |    4 +-\n t/lib-proto-disable.sh                  |   12 +-\n t/lib-submodule-update.sh               |    2 +-\n t/t0001-init.sh                         |   14 +-\n t/t0021-conversion.sh                   |   58 +-\n t/t0210-trace2-normal.sh                |   10 +-\n t/t0211-trace2-perf.sh                  |    4 +-\n t/t0212-trace2-event.sh                 |    2 +-\n t/t1309-early-config.sh                 |    2 +-\n t/t2081-parallel-checkout-collisions.sh |    2 +-\n t/t2082-parallel-checkout-attributes.sh |    4 +-\n t/t3431-rebase-fork-point.sh            |    2 +-\n t/t5505-remote.sh                       | 1132 ++++++++++-------------\n t/t5544-pack-objects-hook.sh            |    6 +-\n t/t5550-http-fetch-dumb.sh              |    8 +-\n t/t5573-pull-verify-signatures.sh       |    6 +-\n t/t5606-clone-options.sh                |   10 +-\n t/t5617-clone-submodules-remote.sh      |    4 +-\n t/t5702-protocol-v2.sh                  |    2 +-\n t/t7814-grep-recurse-submodules.sh      |   16 +-\n t/test-lib-functions.sh                 |  104 ++-\n 24 files changed, 667 insertions(+), 757 deletions(-)\n\n-- \n2.36.1\n\n"},{"id":"457440","messageId":"20220617002036.1577-2-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 1/6] remote: handle negative refspecs in git remote show","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:31Z","receivedAt":"2022-06-17T00:20:45Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.e.keller@intel.com>\n\nBy default, the git remote show command will query data from remotes to\nshow data about what might be done on a future git fetch. This process\ncurrently does not handle negative refspecs. This can be confusing,\nbecause the show command will list refs as if they would be fetched. For\nexample if the fetch refspec \"^refs/heads/pr/*\", it still displays the\nfollowing:\n\n  * remote jdk19\n    Fetch URL: git@github.com:openjdk/jdk19.git\n    Push  URL: git@github.com:openjdk/jdk19.git\n    HEAD branch: master\n    Remote branches:\n      master tracked\n      pr/1   new (next fetch will store in remotes/jdk19)\n      pr/2   new (next fetch will store in remotes/jdk19)\n      pr/3   new (next fetch will store in remotes/jdk19)\n    Local ref configured for 'git push':\n      master pushes to master (fast-forwardable)\n\nFix this by adding an additional check inside of get_ref_states. If a\nref matches one of the negative refspecs, mark it as skipped instead of\nmarking it as new or tracked.\n\nWith this change, we now report remote branches that are skipped due to\nnegative refspecs properly:\n\n  * remote jdk19\n    Fetch URL: git@github.com:openjdk/jdk19.git\n    Push  URL: git@github.com:openjdk/jdk19.git\n    HEAD branch: master\n    Remote branches:\n      master tracked\n      pr/1   skipped\n      pr/2   skipped\n      pr/3   skipped\n    Local ref configured for 'git push':\n      master pushes to master (fast-forwardable)\n\nBy showing the refs as skipped, it helps clarify that these references\nwon't actually be fetched.\n\nThis does not properly handle refs going stale due to a newly added\nnegative refspec. In addition, git remote prune doesn't handle that\nnegative refspec case either. Fixing that requires digging into\nget_stale_heads and handling the case of a ref which exists on the\nremote but is omitted due to a negative refspec locally.\n\nAdd a new test case which covers the functionality above, as well as a\nnew expected failure indicating the poor overlap with stale refs.\n\nReported-by: Pavel Rappo <pavel.rappo@gmail.com>\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n builtin/remote.c  | 12 ++++++++++--\n remote.c          |  2 +-\n remote.h          |  6 ++++++\n t/t5505-remote.sh | 46 ++++++++++++++++++++++++++++++++++++++++++++++\n 4 files changed, 63 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/remote.c b/builtin/remote.c\nindex d4b69fe77898..d9b8746cb3cb 100644\n--- a/builtin/remote.c\n+++ b/builtin/remote.c\n@@ -344,12 +344,13 @@ static void read_branches(void)\n \n struct ref_states {\n \tstruct remote *remote;\n-\tstruct string_list new_refs, stale, tracked, heads, push;\n+\tstruct string_list new_refs, skipped, stale, tracked, heads, push;\n \tint queried;\n };\n \n #define REF_STATES_INIT { \\\n \t.new_refs = STRING_LIST_INIT_DUP, \\\n+\t.skipped = STRING_LIST_INIT_DUP, \\\n \t.stale = STRING_LIST_INIT_DUP, \\\n \t.tracked = STRING_LIST_INIT_DUP, \\\n \t.heads = STRING_LIST_INIT_DUP, \\\n@@ -368,7 +369,9 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat\n \t\t\t\tstates->remote->fetch.raw[i]);\n \n \tfor (ref = fetch_map; ref; ref = ref->next) {\n-\t\tif (!ref->peer_ref || !ref_exists(ref->peer_ref->name))\n+\t\tif (omit_name_by_refspec(ref->name, &states->remote->fetch))\n+\t\t\tstring_list_append(&states->skipped, abbrev_branch(ref->name));\n+\t\telse if (!ref->peer_ref || !ref_exists(ref->peer_ref->name))\n \t\t\tstring_list_append(&states->new_refs, abbrev_branch(ref->name));\n \t\telse\n \t\t\tstring_list_append(&states->tracked, abbrev_branch(ref->name));\n@@ -383,6 +386,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat\n \tfree_refs(fetch_map);\n \n \tstring_list_sort(&states->new_refs);\n+\tstring_list_sort(&states->skipped);\n \tstring_list_sort(&states->tracked);\n \tstring_list_sort(&states->stale);\n \n@@ -941,6 +945,7 @@ static void clear_push_info(void *util, const char *string)\n static void free_remote_ref_states(struct ref_states *states)\n {\n \tstring_list_clear(&states->new_refs, 0);\n+\tstring_list_clear(&states->skipped, 0);\n \tstring_list_clear(&states->stale, 1);\n \tstring_list_clear(&states->tracked, 0);\n \tstring_list_clear(&states->heads, 0);\n@@ -1035,6 +1040,8 @@ static int show_remote_info_item(struct string_list_item *item, void *cb_data)\n \t\t\targ = states->remote->name;\n \t\t} else if (string_list_has_string(&states->tracked, name))\n \t\t\targ = _(\" tracked\");\n+\t\telse if (string_list_has_string(&states->skipped, name))\n+\t\t\targ = _(\" skipped\");\n \t\telse if (string_list_has_string(&states->stale, name))\n \t\t\targ = _(\" stale (use 'git remote prune' to remove)\");\n \t\telse\n@@ -1308,6 +1315,7 @@ static int show(int argc, const char **argv)\n \t\t/* remote branch info */\n \t\tinfo.width = 0;\n \t\tfor_each_string_list(&info.states.new_refs, add_remote_to_show_info, &info);\n+\t\tfor_each_string_list(&info.states.skipped, add_remote_to_show_info, &info);\n \t\tfor_each_string_list(&info.states.tracked, add_remote_to_show_info, &info);\n \t\tfor_each_string_list(&info.states.stale, add_remote_to_show_info, &info);\n \t\tif (info.list.nr)\ndiff --git a/remote.c b/remote.c\nindex 404e1e0a0ddb..7d68b5632bb5 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -804,7 +804,7 @@ static int refspec_match(const struct refspec_item *refspec,\n \treturn !strcmp(refspec->src, name);\n }\n \n-static int omit_name_by_refspec(const char *name, struct refspec *rs)\n+int omit_name_by_refspec(const char *name, struct refspec *rs)\n {\n \tint i;\n \ndiff --git a/remote.h b/remote.h\nindex dd4402436f1f..448675e11259 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -247,6 +247,12 @@ int resolve_remote_symref(struct ref *ref, struct ref *list);\n  */\n struct ref *ref_remove_duplicates(struct ref *ref_map);\n \n+/*\n+ * Check whether a name matches any negative refspec in rs. Returns 1 if the\n+ * name matches at least one negative refspec, and 0 otherwise.\n+ */\n+int omit_name_by_refspec(const char *name, struct refspec *rs);\n+\n /*\n  * Remove all entries in the input list which match any negative refspec in\n  * the refspec list.\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex fff14e13ed43..0aad0eb4d26c 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -302,6 +302,52 @@ test_expect_success 'show' '\n \t)\n '\n \n+cat >expect <<EOF\n+* remote origin\n+  Fetch URL: $(pwd)/one\n+  Push  URL: $(pwd)/one\n+  HEAD branch: main\n+  Remote branches:\n+    main skipped\n+    side tracked\n+  Local branches configured for 'git pull':\n+    ahead merges with remote main\n+    main  merges with remote main\n+  Local refs configured for 'git push':\n+    main pushes to main     (local out of date)\n+    main pushes to upstream (create)\n+EOF\n+\n+test_expect_success 'show with negative refspecs' '\n+\ttest_when_finished \"git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/main\" &&\n+\tgit -C test config --add remote.origin.fetch ^refs/heads/main &&\n+\tgit -C test remote show origin >output &&\n+\ttest_cmp expect output\n+'\n+\n+cat >expect <<EOF\n+* remote origin\n+  Fetch URL: $(pwd)/one\n+  Push  URL: $(pwd)/one\n+  HEAD branch: main\n+  Remote branches:\n+    main new (next fetch will store in remotes/origin)\n+    side stale (use 'git remote prune' to remove)\n+  Local branches configured for 'git pull':\n+    ahead merges with remote main\n+    main  merges with remote main\n+  Local refs configured for 'git push':\n+    main pushes to main     (local out of date)\n+    main pushes to upstream (create)\n+EOF\n+\n+test_expect_failure 'show stale with negative refspecs' '\n+\ttest_when_finished \"git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/side\" &&\n+\tgit -C test config --add remote.origin.fetch ^refs/heads/side &&\n+\tgit -C test remote show origin >output &&\n+\ttest_cmp expect output\n+'\n+\n cat >test/expect <<EOF\n * remote origin\n   Fetch URL: $(pwd)/one\n-- \n2.36.1\n\n"},{"id":"457441","messageId":"20220617002036.1577-4-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 3/6] tests: handle --global directly in test_config/test_unconfig","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:33Z","receivedAt":"2022-06-17T00:20:48Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.e.keller@intel.com>\n\nThe test_config function is used to set a configuration value and then\nensure its unset at the end of the test. The test_config_global function\ndoes the same, but for global values.\n\nInstead of having two separate functions, handle the '--global' option\nin test_config and test_unconfig. This matches more closely with \"git\nconfig\" syntax and paves the way for additional optional argument\nhandling.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n t/lib-parallel-checkout.sh              |  4 +-\n t/lib-proto-disable.sh                  | 12 ++---\n t/lib-submodule-update.sh               |  2 +-\n t/t0001-init.sh                         | 14 ++---\n t/t0021-conversion.sh                   | 58 ++++++++++----------\n t/t0210-trace2-normal.sh                | 10 ++--\n t/t0211-trace2-perf.sh                  |  4 +-\n t/t0212-trace2-event.sh                 |  2 +-\n t/t1309-early-config.sh                 |  2 +-\n t/t2081-parallel-checkout-collisions.sh |  2 +-\n t/t2082-parallel-checkout-attributes.sh |  4 +-\n t/t3431-rebase-fork-point.sh            |  2 +-\n t/t5505-remote.sh                       | 12 ++---\n t/t5544-pack-objects-hook.sh            |  6 +--\n t/t5550-http-fetch-dumb.sh              |  8 +--\n t/t5573-pull-verify-signatures.sh       |  6 +--\n t/t5606-clone-options.sh                | 10 ++--\n t/t5617-clone-submodules-remote.sh      |  4 +-\n t/t5702-protocol-v2.sh                  |  2 +-\n t/t7814-grep-recurse-submodules.sh      | 16 +++---\n t/test-lib-functions.sh                 | 72 ++++++++++++++++++-------\n 21 files changed, 144 insertions(+), 108 deletions(-)\n\ndiff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh\nindex 83b279a846c6..7a1a1f2b75b9 100644\n--- a/t/lib-parallel-checkout.sh\n+++ b/t/lib-parallel-checkout.sh\n@@ -9,8 +9,8 @@ set_checkout_config () {\n \t\tBUG \"usage: set_checkout_config <workers> <threshold>\"\n \tfi &&\n \n-\ttest_config_global checkout.workers $1 &&\n-\ttest_config_global checkout.thresholdForParallelism $2\n+\ttest_config --global checkout.workers $1 &&\n+\ttest_config --global checkout.thresholdForParallelism $2\n }\n \n # Run \"${@:2}\" and check that $1 checkout workers were used\ndiff --git a/t/lib-proto-disable.sh b/t/lib-proto-disable.sh\nindex 83babe57d959..f3cb43ae1aab 100644\n--- a/t/lib-proto-disable.sh\n+++ b/t/lib-proto-disable.sh\n@@ -147,33 +147,33 @@ test_config () {\n \t# Test clone/fetch/push with protocol.allow user defined default\n \ttest_expect_success \"clone $desc (enabled)\" '\n \t\trm -rf tmp.git &&\n-\t\ttest_config_global protocol.allow always &&\n+\t\ttest_config --global protocol.allow always &&\n \t\tgit clone --bare \"$url\" tmp.git\n \t'\n \n \ttest_expect_success \"fetch $desc (enabled)\" '\n-\t\ttest_config_global protocol.allow always &&\n+\t\ttest_config --global protocol.allow always &&\n \t\tgit -C tmp.git fetch\n \t'\n \n \ttest_expect_success \"push $desc (enabled)\" '\n-\t\ttest_config_global protocol.allow always &&\n+\t\ttest_config --global protocol.allow always &&\n \t\tgit -C tmp.git push origin HEAD:pushed\n \t'\n \n \ttest_expect_success \"push $desc (disabled)\" '\n-\t\ttest_config_global protocol.allow never &&\n+\t\ttest_config --global protocol.allow never &&\n \t\ttest_must_fail git -C tmp.git push origin HEAD:pushed\n \t'\n \n \ttest_expect_success \"fetch $desc (disabled)\" '\n-\t\ttest_config_global protocol.allow never &&\n+\t\ttest_config --global protocol.allow never &&\n \t\ttest_must_fail git -C tmp.git fetch\n \t'\n \n \ttest_expect_success \"clone $desc (disabled)\" '\n \t\trm -rf tmp.git &&\n-\t\ttest_config_global protocol.allow never &&\n+\t\ttest_config --global protocol.allow never &&\n \t\ttest_must_fail git clone --bare \"$url\" tmp.git\n \t'\n }\ndiff --git a/t/lib-submodule-update.sh b/t/lib-submodule-update.sh\nindex f7c7df0ca427..17d95b8193a9 100644\n--- a/t/lib-submodule-update.sh\n+++ b/t/lib-submodule-update.sh\n@@ -198,7 +198,7 @@ test_git_directory_exists () {\n # settings for diff.ignoreSubmodules.\n prolog () {\n \t(test -d submodule_update_repo || create_lib_submodule_repo) &&\n-\ttest_config_global diff.ignoreSubmodules all &&\n+\ttest_config --global diff.ignoreSubmodules all &&\n \ttest_config diff.ignoreSubmodules all\n }\n \ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex d479303efa03..42242ca5ee0a 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -200,7 +200,7 @@ init_no_templatedir_env () {\n test_expect_success 'init with init.templatedir set' '\n \tmkdir templatedir-source &&\n \techo Content >templatedir-source/file &&\n-\ttest_config_global init.templatedir \"${HOME}/templatedir-source\" &&\n+\ttest_config --global init.templatedir \"${HOME}/templatedir-source\" &&\n \n \tinit_no_templatedir_env templatedir-set &&\n \ttest_cmp templatedir-source/file templatedir-set/.git/file\n@@ -209,15 +209,15 @@ test_expect_success 'init with init.templatedir set' '\n test_expect_success 'init with init.templatedir using ~ expansion' '\n \tmkdir -p templatedir-source &&\n \techo Content >templatedir-source/file &&\n-\ttest_config_global init.templatedir \"~/templatedir-source\" &&\n+\ttest_config --global init.templatedir \"~/templatedir-source\" &&\n \n \tinit_no_templatedir_env templatedir-expansion &&\n \ttest_cmp templatedir-source/file templatedir-expansion/.git/file\n '\n \n test_expect_success 'init --bare/--shared overrides system/global config' '\n-\ttest_config_global core.bare false &&\n-\ttest_config_global core.sharedRepository 0640 &&\n+\ttest_config --global core.bare false &&\n+\ttest_config --global core.sharedRepository 0640 &&\n \tgit init --bare --shared=0666 init-bare-shared-override &&\n \tcheck_config init-bare-shared-override true unset &&\n \ttest x0666 = \\\n@@ -225,7 +225,7 @@ test_expect_success 'init --bare/--shared overrides system/global config' '\n '\n \n test_expect_success 'init honors global core.sharedRepository' '\n-\ttest_config_global core.sharedRepository 0666 &&\n+\ttest_config --global core.sharedRepository 0666 &&\n \tgit init shared-honor-global &&\n \ttest x0666 = \\\n \tx$(git config -f shared-honor-global/.git/config core.sharedRepository)\n@@ -569,7 +569,7 @@ test_expect_success '--initial-branch' '\n '\n \n test_expect_success 'overridden default initial branch name (config)' '\n-\ttest_config_global init.defaultBranch nmb &&\n+\ttest_config --global init.defaultBranch nmb &&\n \tGIT_TEST_DEFAULT_INITIAL_BRANCH_NAME= git init initial-branch-config &&\n \tgit -C initial-branch-config symbolic-ref HEAD >actual &&\n \tgrep nmb actual\n@@ -583,7 +583,7 @@ test_expect_success 'advice on unconfigured init.defaultBranch' '\n '\n \n test_expect_success 'overridden default main branch name (env)' '\n-\ttest_config_global init.defaultBranch nmb &&\n+\ttest_config --global init.defaultBranch nmb &&\n \tGIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=env git init main-branch-env &&\n \tgit -C main-branch-env symbolic-ref HEAD >actual &&\n \tgrep env actual\ndiff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh\nindex bad37abad2c3..119004ed9c58 100755\n--- a/t/t0021-conversion.sh\n+++ b/t/t0021-conversion.sh\n@@ -339,8 +339,8 @@ test_expect_success \"filter: smudge empty file\" '\n '\n \n test_expect_success 'disable filter with empty override' '\n-\ttest_config_global filter.disable.smudge false &&\n-\ttest_config_global filter.disable.clean false &&\n+\ttest_config --global filter.disable.smudge false &&\n+\ttest_config --global filter.disable.clean false &&\n \ttest_config filter.disable.smudge false &&\n \ttest_config filter.disable.clean false &&\n \n@@ -366,8 +366,8 @@ test_expect_success 'diff does not reuse worktree files that need cleaning' '\n '\n \n test_expect_success PERL 'required process filter should filter data' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.required true &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -451,8 +451,8 @@ test_expect_success PERL 'required process filter should filter data' '\n '\n \n test_expect_success PERL 'required process filter should filter data for various subcommands' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.required true &&\n \t(\n \t\tcd repo &&\n \n@@ -562,9 +562,9 @@ test_expect_success PERL 'required process filter should filter data for various\n '\n \n test_expect_success PERL 'required process filter takes precedence' '\n-\ttest_config_global filter.protocol.clean false &&\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean\" &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.clean false &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean\" &&\n+\ttest_config --global filter.protocol.required true &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -588,7 +588,7 @@ test_expect_success PERL 'required process filter takes precedence' '\n '\n \n test_expect_success PERL 'required process filter should be used only for \"clean\" operation only' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean\" &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean\" &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -623,8 +623,8 @@ test_expect_success PERL 'required process filter should be used only for \"clean\n '\n \n test_expect_success PERL 'required process filter should process multiple packets' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.required true &&\n \n \trm -rf repo &&\n \tmkdir repo &&\n@@ -688,8 +688,8 @@ test_expect_success PERL 'required process filter should process multiple packet\n '\n \n test_expect_success PERL 'required process filter with clean error should fail' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.required true &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -707,7 +707,7 @@ test_expect_success PERL 'required process filter with clean error should fail'\n '\n \n test_expect_success PERL 'process filter should restart after unexpected write failure' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -762,7 +762,7 @@ test_expect_success PERL 'process filter should restart after unexpected write f\n '\n \n test_expect_success PERL 'process filter should not be restarted if it signals an error' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -805,7 +805,7 @@ test_expect_success PERL 'process filter should not be restarted if it signals a\n '\n \n test_expect_success PERL 'process filter abort stops processing of all further files' '\n-\ttest_config_global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n+\ttest_config --global filter.protocol.process \"rot13-filter.pl debug.log clean smudge\" &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -845,8 +845,8 @@ test_expect_success PERL 'process filter abort stops processing of all further f\n '\n \n test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n-\ttest_config_global filter.protocol.process cat &&\n-\ttest_config_global filter.protocol.required true &&\n+\ttest_config --global filter.protocol.process cat &&\n+\ttest_config --global filter.protocol.required true &&\n \trm -rf repo &&\n \tmkdir repo &&\n \t(\n@@ -862,10 +862,10 @@ test_expect_success PERL 'invalid process filter must fail (and not hang!)' '\n '\n \n test_expect_success PERL 'delayed checkout in process filter' '\n-\ttest_config_global filter.a.process \"rot13-filter.pl a.log clean smudge delay\" &&\n-\ttest_config_global filter.a.required true &&\n-\ttest_config_global filter.b.process \"rot13-filter.pl b.log clean smudge delay\" &&\n-\ttest_config_global filter.b.required true &&\n+\ttest_config --global filter.a.process \"rot13-filter.pl a.log clean smudge delay\" &&\n+\ttest_config --global filter.a.required true &&\n+\ttest_config --global filter.b.process \"rot13-filter.pl b.log clean smudge delay\" &&\n+\ttest_config --global filter.b.required true &&\n \n \trm -rf repo &&\n \tmkdir repo &&\n@@ -941,8 +941,8 @@ test_expect_success PERL 'delayed checkout in process filter' '\n '\n \n test_expect_success PERL 'missing file in delayed checkout' '\n-\ttest_config_global filter.bug.process \"rot13-filter.pl bug.log clean smudge delay\" &&\n-\ttest_config_global filter.bug.required true &&\n+\ttest_config --global filter.bug.process \"rot13-filter.pl bug.log clean smudge delay\" &&\n+\ttest_config --global filter.bug.required true &&\n \n \trm -rf repo &&\n \tmkdir repo &&\n@@ -961,8 +961,8 @@ test_expect_success PERL 'missing file in delayed checkout' '\n '\n \n test_expect_success PERL 'invalid file in delayed checkout' '\n-\ttest_config_global filter.bug.process \"rot13-filter.pl bug.log clean smudge delay\" &&\n-\ttest_config_global filter.bug.required true &&\n+\ttest_config --global filter.bug.process \"rot13-filter.pl bug.log clean smudge delay\" &&\n+\ttest_config --global filter.bug.required true &&\n \n \trm -rf repo &&\n \tmkdir repo &&\n@@ -992,9 +992,9 @@ do\n \n \ttest_expect_success PERL,SYMLINKS,$mode_prereq \\\n \t\"delayed checkout with $mode-collision don't write to the wrong place\" '\n-\t\ttest_config_global filter.delay.process \\\n+\t\ttest_config --global filter.delay.process \\\n \t\t\t\"\\\"$TEST_ROOT/rot13-filter.pl\\\" --always-delay delayed.log clean smudge delay\" &&\n-\t\ttest_config_global filter.delay.required true &&\n+\t\ttest_config --global filter.delay.required true &&\n \n \t\tgit init $mode-collision &&\n \t\t(\ndiff --git a/t/t0210-trace2-normal.sh b/t/t0210-trace2-normal.sh\nindex 80e76a4695ed..210b99ec9c1b 100755\n--- a/t/t0210-trace2-normal.sh\n+++ b/t/t0210-trace2-normal.sh\n@@ -251,8 +251,8 @@ sane_unset GIT_TRACE2_BRIEF\n \n test_expect_success 'using global config, normal stream, return code 0' '\n \ttest_when_finished \"rm trace.normal actual expect\" &&\n-\ttest_config_global trace2.normalBrief 1 &&\n-\ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n+\ttest_config --global trace2.normalBrief 1 &&\n+\ttest_config --global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \ttest-tool trace2 001return 0 &&\n \tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n \tcat >expect <<-EOF &&\n@@ -267,10 +267,10 @@ test_expect_success 'using global config, normal stream, return code 0' '\n \n test_expect_success 'using global config with include' '\n \ttest_when_finished \"rm trace.normal actual expect real.gitconfig\" &&\n-\ttest_config_global trace2.normalBrief 1 &&\n-\ttest_config_global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n+\ttest_config --global trace2.normalBrief 1 &&\n+\ttest_config --global trace2.normalTarget \"$(pwd)/trace.normal\" &&\n \tmv \"$(pwd)/.gitconfig\" \"$(pwd)/real.gitconfig\" &&\n-\ttest_config_global include.path \"$(pwd)/real.gitconfig\" &&\n+\ttest_config --global include.path \"$(pwd)/real.gitconfig\" &&\n \ttest-tool trace2 001return 0 &&\n \tperl \"$TEST_DIRECTORY/t0210/scrub_normal.perl\" <trace.normal >actual &&\n \tcat >expect <<-EOF &&\ndiff --git a/t/t0211-trace2-perf.sh b/t/t0211-trace2-perf.sh\nindex 22d0845544e9..1196fe9c1131 100755\n--- a/t/t0211-trace2-perf.sh\n+++ b/t/t0211-trace2-perf.sh\n@@ -159,8 +159,8 @@ sane_unset GIT_TRACE2_PERF_BRIEF\n \n test_expect_success 'using global config, perf stream, return code 0' '\n \ttest_when_finished \"rm trace.perf actual expect\" &&\n-\ttest_config_global trace2.perfBrief 1 &&\n-\ttest_config_global trace2.perfTarget \"$(pwd)/trace.perf\" &&\n+\ttest_config --global trace2.perfBrief 1 &&\n+\ttest_config --global trace2.perfTarget \"$(pwd)/trace.perf\" &&\n \ttest-tool trace2 001return 0 &&\n \tperl \"$TEST_DIRECTORY/t0211/scrub_perf.perl\" <trace.perf >actual &&\n \tcat >expect <<-EOF &&\ndiff --git a/t/t0212-trace2-event.sh b/t/t0212-trace2-event.sh\nindex 6d3374ff773c..39828f3345ef 100755\n--- a/t/t0212-trace2-event.sh\n+++ b/t/t0212-trace2-event.sh\n@@ -277,7 +277,7 @@ test_expect_success JSON_PP 'basic trace2_data' '\n \n test_expect_success JSON_PP 'using global config, event stream, error event' '\n \ttest_when_finished \"rm trace.event actual expect\" &&\n-\ttest_config_global trace2.eventTarget \"$(pwd)/trace.event\" &&\n+\ttest_config --global trace2.eventTarget \"$(pwd)/trace.event\" &&\n \ttest-tool trace2 003error \"hello world\" \"this is a test\" &&\n \tperl \"$TEST_DIRECTORY/t0212/parse_events.perl\" <trace.event >actual &&\n \tsed -e \"s/^|//\" >expect <<-EOF &&\ndiff --git a/t/t1309-early-config.sh b/t/t1309-early-config.sh\nindex 537435b90ae9..db30478260b3 100755\n--- a/t/t1309-early-config.sh\n+++ b/t/t1309-early-config.sh\n@@ -96,7 +96,7 @@ test_expect_success 'early config and onbranch' '\n '\n \n test_expect_success 'onbranch config outside of git repo' '\n-\ttest_config_global includeIf.onbranch:topic.path non-existent &&\n+\ttest_config --global includeIf.onbranch:topic.path non-existent &&\n \tnongit git help\n '\n \ndiff --git a/t/t2081-parallel-checkout-collisions.sh b/t/t2081-parallel-checkout-collisions.sh\nindex 6acdb89d12bd..76638658265b 100755\n--- a/t/t2081-parallel-checkout-collisions.sh\n+++ b/t/t2081-parallel-checkout-collisions.sh\n@@ -138,7 +138,7 @@ test_expect_success CASE_INSENSITIVE_FS 'collision report on clone (w/ racy file\n test_expect_success CASE_INSENSITIVE_FS,!MINGW,!CYGWIN \\\n \t'collision report on clone (w/ colliding peer after the detected entry)' '\n \n-\ttest_config_global filter.logger.smudge \"\\\"$TEST_ROOT/logger_script\\\" %f\" &&\n+\ttest_config --global filter.logger.smudge \"\\\"$TEST_ROOT/logger_script\\\" %f\" &&\n \tgit reset --hard basename_collision &&\n \techo \"file_x filter=logger\" >.gitattributes &&\n \tgit add .gitattributes &&\ndiff --git a/t/t2082-parallel-checkout-attributes.sh b/t/t2082-parallel-checkout-attributes.sh\nindex 252545796182..f90dd7f156d4 100755\n--- a/t/t2082-parallel-checkout-attributes.sh\n+++ b/t/t2082-parallel-checkout-attributes.sh\n@@ -142,9 +142,9 @@ test_expect_success PERL 'parallel-checkout and delayed checkout' '\n \twrite_script rot13-filter.pl \"$PERL_PATH\" \\\n \t\t<\"$TEST_DIRECTORY\"/t0021/rot13-filter.pl &&\n \n-\ttest_config_global filter.delay.process \\\n+\ttest_config --global filter.delay.process \\\n \t\t\"\\\"$(pwd)/rot13-filter.pl\\\" --always-delay \\\"$(pwd)/delayed.log\\\" clean smudge delay\" &&\n-\ttest_config_global filter.delay.required true &&\n+\ttest_config --global filter.delay.required true &&\n \n \techo \"abcd\" >original &&\n \techo \"nopq\" >rot13 &&\ndiff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh\nindex 1d0b15380edf..97aa15b673fa 100755\n--- a/t/t3431-rebase-fork-point.sh\n+++ b/t/t3431-rebase-fork-point.sh\n@@ -92,7 +92,7 @@ test_expect_success 'rebase.forkPoint set to false' '\n '\n \n test_expect_success 'rebase.forkPoint set to false and then to true' '\n-\ttest_config_global rebase.forkPoint false &&\n+\ttest_config --global rebase.forkPoint false &&\n \ttest_config rebase.forkPoint true &&\n \tdo_test_rebase \"G F E D B A\"\n '\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex c4228a27a71f..7914379ed253 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -668,7 +668,7 @@ test_expect_success 'reject adding remote with an invalid name' '\n # the last two ones check if the config is updated.\n \n test_expect_success 'rename a remote' '\n-\ttest_config_global remote.pushDefault origin &&\n+\ttest_config --global remote.pushDefault origin &&\n \tgit clone one four &&\n \tgit -C four config branch.main.pushRemote origin &&\n \tGIT_TRACE2_EVENT=$(pwd)/trace \\\n@@ -693,7 +693,7 @@ test_expect_success 'rename a remote renames repo remote.pushDefault' '\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n-\ttest_config_global remote.pushDefault other &&\n+\ttest_config --global remote.pushDefault other &&\n \tgit clone one four.2 &&\n \tgit -C four.2 config remote.pushDefault origin &&\n \tgit -C four.2 remote rename origin upstream &&\n@@ -702,7 +702,7 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but ignores\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n-\ttest_config_global remote.pushDefault origin &&\n+\ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.3 &&\n \tgit -C four.3 config remote.pushDefault origin &&\n \tgit -C four.3 remote rename origin upstream &&\n@@ -740,7 +740,7 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n '\n \n test_expect_success 'remove a remote' '\n-\ttest_config_global remote.pushDefault origin &&\n+\ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.five &&\n \tgit -C four.five config branch.main.pushRemote origin &&\n \tgit -C four.five remote remove origin &&\n@@ -758,7 +758,7 @@ test_expect_success 'remove a remote removes repo remote.pushDefault' '\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n-\ttest_config_global remote.pushDefault other &&\n+\ttest_config --global remote.pushDefault other &&\n \tgit clone one four.five.2 &&\n \tgit -C four.five.2 config remote.pushDefault origin &&\n \tgit -C four.five.2 remote remove origin &&\n@@ -767,7 +767,7 @@ test_expect_success 'remove a remote removes repo remote.pushDefault but ignores\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n-\ttest_config_global remote.pushDefault origin &&\n+\ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.five.3 &&\n \tgit -C four.five.3 config remote.pushDefault origin &&\n \tgit -C four.five.3 remote remove origin &&\ndiff --git a/t/t5544-pack-objects-hook.sh b/t/t5544-pack-objects-hook.sh\nindex dd5f44d986f2..7acea482224a 100755\n--- a/t/t5544-pack-objects-hook.sh\n+++ b/t/t5544-pack-objects-hook.sh\n@@ -24,7 +24,7 @@ clear_hook_results () {\n \n test_expect_success 'hook runs via global config' '\n \tclear_hook_results &&\n-\ttest_config_global uploadpack.packObjectsHook ./hook &&\n+\ttest_config --global uploadpack.packObjectsHook ./hook &&\n \tgit clone --no-local . dst.git 2>stderr &&\n \tgrep \"hook running\" stderr\n '\n@@ -61,8 +61,8 @@ test_expect_success 'hook does not run from repo config' '\n \n test_expect_success 'hook works with partial clone' '\n \tclear_hook_results &&\n-\ttest_config_global uploadpack.packObjectsHook ./hook &&\n-\ttest_config_global uploadpack.allowFilter true &&\n+\ttest_config --global uploadpack.packObjectsHook ./hook &&\n+\ttest_config --global uploadpack.allowFilter true &&\n \tgit clone --bare --no-local --filter=blob:none . dst.git &&\n \tgit -C dst.git rev-list --objects --missing=allow-any --no-object-names --all >objects &&\n \tgit -C dst.git cat-file --batch-check=\"%(objecttype)\" <objects >types &&\ndiff --git a/t/t5550-http-fetch-dumb.sh b/t/t5550-http-fetch-dumb.sh\nindex f0d9cd584d3b..e97f94f1db68 100755\n--- a/t/t5550-http-fetch-dumb.sh\n+++ b/t/t5550-http-fetch-dumb.sh\n@@ -100,7 +100,7 @@ test_expect_success 'http auth can request both user and pass' '\n '\n \n test_expect_success 'http auth respects credential helper config' '\n-\ttest_config_global credential.helper \"!f() {\n+\ttest_config --global credential.helper \"!f() {\n \t\tcat >/dev/null\n \t\techo username=user@host\n \t\techo password=pass@host\n@@ -111,14 +111,14 @@ test_expect_success 'http auth respects credential helper config' '\n '\n \n test_expect_success 'http auth can get username from config' '\n-\ttest_config_global \"credential.$HTTPD_URL.username\" user@host &&\n+\ttest_config --global \"credential.$HTTPD_URL.username\" user@host &&\n \tset_askpass wrong pass@host &&\n \tgit clone \"$HTTPD_URL/auth/dumb/repo.git\" clone-auth-user &&\n \texpect_askpass pass user@host\n '\n \n test_expect_success 'configured username does not override URL' '\n-\ttest_config_global \"credential.$HTTPD_URL.username\" wrong &&\n+\ttest_config --global \"credential.$HTTPD_URL.username\" wrong &&\n \tset_askpass wrong pass@host &&\n \tgit clone \"$HTTPD_URL_USER/auth/dumb/repo.git\" clone-auth-user2 &&\n \texpect_askpass pass user@host\n@@ -452,7 +452,7 @@ test_expect_success 'http-alternates cannot point at funny protocols' '\n test_expect_success 'http-alternates triggers not-from-user protocol check' '\n \techo \"$HTTPD_URL/dumb/victim.git/objects\" \\\n \t\t>\"$evil/objects/info/http-alternates\" &&\n-\ttest_config_global http.followRedirects true &&\n+\ttest_config --global http.followRedirects true &&\n \ttest_must_fail git -c protocol.http.allow=user \\\n \t\tclone $HTTPD_URL/dumb/evil.git evil-user &&\n \tgit -c protocol.http.allow=always \\\ndiff --git a/t/t5573-pull-verify-signatures.sh b/t/t5573-pull-verify-signatures.sh\nindex a53dd8550d0b..bc61ee3ef56f 100755\n--- a/t/t5573-pull-verify-signatures.sh\n+++ b/t/t5573-pull-verify-signatures.sh\n@@ -126,7 +126,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature\n test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=ultimate' '\n \ttest_when_finished \"rm -rf empty-repo\" &&\n \tgit init empty-repo &&\n-\ttest_config_global gpg.minTrustLevel ultimate &&\n+\ttest_config --global gpg.minTrustLevel ultimate &&\n \ttest_must_fail \\\n \t\tgit -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&\n \ttest_i18ngrep \"has an untrusted GPG signature\" pullerror\n@@ -135,7 +135,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature\n test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=marginal' '\n \ttest_when_finished \"rm -rf empty-repo\" &&\n \tgit init empty-repo &&\n-\ttest_config_global gpg.minTrustLevel marginal &&\n+\ttest_config --global gpg.minTrustLevel marginal &&\n \ttest_must_fail \\\n \t\tgit -C empty-repo pull --ff-only --verify-signatures ../untrusted 2>pullerror &&\n \ttest_i18ngrep \"has an untrusted GPG signature\" pullerror\n@@ -144,7 +144,7 @@ test_expect_success GPG 'pull commit into unborn branch with untrusted signature\n test_expect_success GPG 'pull commit into unborn branch with untrusted signature and --verify-signatures and minTrustLevel=undefined' '\n \ttest_when_finished \"rm -rf empty-repo\" &&\n \tgit init empty-repo &&\n-\ttest_config_global gpg.minTrustLevel undefined &&\n+\ttest_config --global gpg.minTrustLevel undefined &&\n \tgit -C empty-repo pull --ff-only --verify-signatures ../untrusted >pulloutput &&\n \ttest_i18ngrep \"has a good GPG signature\" pulloutput\n '\ndiff --git a/t/t5606-clone-options.sh b/t/t5606-clone-options.sh\nindex 8f676d6b0c0e..a7efedfb79a5 100755\n--- a/t/t5606-clone-options.sh\n+++ b/t/t5606-clone-options.sh\n@@ -18,11 +18,11 @@ test_expect_success 'setup' '\n \n test_expect_success 'submodule.stickyRecursiveClone flag manipulates submodule.recurse value' '\n \n-\ttest_config_global submodule.stickyRecursiveClone true &&\n+\ttest_config --global submodule.stickyRecursiveClone true &&\n \tgit clone --recurse-submodules parent clone_recurse_true &&\n \ttest_cmp_config -C clone_recurse_true true submodule.recurse &&\n \n-\ttest_config_global submodule.stickyRecursiveClone false &&\n+\ttest_config --global submodule.stickyRecursiveClone false &&\n \tgit clone --recurse-submodules parent clone_recurse_false &&\n \ttest_expect_code 1 git -C clone_recurse_false config --get submodule.recurse\n \n@@ -94,7 +94,7 @@ test_expect_success 'prefers --template config over normal config' '\n \ttemplate=\"$TRASH_DIRECTORY/template-with-config\" &&\n \tmkdir \"$template\" &&\n \tgit config --file \"$template/config\" foo.bar from_template &&\n-\ttest_config_global foo.bar from_global &&\n+\ttest_config --global foo.bar from_global &&\n \tgit clone \"--template=$template\" parent clone-template-config &&\n \ttest \"$(git -C clone-template-config config --local foo.bar)\" = \"from_template\"\n \n@@ -112,7 +112,7 @@ test_expect_success 'prefers -c config over --template config' '\n \n test_expect_success 'prefers config \"clone.defaultRemoteName\" over default' '\n \n-\ttest_config_global clone.defaultRemoteName from_config &&\n+\ttest_config --global clone.defaultRemoteName from_config &&\n \tgit clone parent clone-config-origin &&\n \tgit -C clone-config-origin rev-parse --verify refs/remotes/from_config/main\n \n@@ -142,7 +142,7 @@ test_expect_success 'redirected clone -v does show progress' '\n '\n \n test_expect_success 'clone does not segfault with --bare and core.bare=false' '\n-\ttest_config_global core.bare false &&\n+\ttest_config --global core.bare false &&\n \tgit clone --bare parent clone-bare &&\n \techo true >expect &&\n \tgit -C clone-bare rev-parse --is-bare-repository >actual &&\ndiff --git a/t/t5617-clone-submodules-remote.sh b/t/t5617-clone-submodules-remote.sh\nindex ca8f80083a2f..b92f2e5ca470 100755\n--- a/t/t5617-clone-submodules-remote.sh\n+++ b/t/t5617-clone-submodules-remote.sh\n@@ -87,7 +87,7 @@ test_expect_success 'clone with --filter' '\n # check that clone.filterSubmodules works (--also-filter-submodules can be\n # omitted)\n test_expect_success 'filters applied with clone.filterSubmodules' '\n-\ttest_config_global clone.filterSubmodules true &&\n+\ttest_config --global clone.filterSubmodules true &&\n \tgit clone --recurse-submodules --filter blob:none \\\n \t\t\"file://$pwd/srv.bare\" super_clone2 &&\n \ttest_cmp_config -C super_clone2 true remote.origin.promisor &&\n@@ -97,7 +97,7 @@ test_expect_success 'filters applied with clone.filterSubmodules' '\n '\n \n test_expect_success '--no-also-filter-submodules overrides clone.filterSubmodules=true' '\n-\ttest_config_global clone.filterSubmodules true &&\n+\ttest_config --global clone.filterSubmodules true &&\n \tgit clone --recurse-submodules --filter blob:none \\\n \t\t--no-also-filter-submodules \\\n \t\t\"file://$pwd/srv.bare\" super_clone3 &&\ndiff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh\nindex 00ce9aec2346..d7ac417bacb6 100755\n--- a/t/t5702-protocol-v2.sh\n+++ b/t/t5702-protocol-v2.sh\n@@ -341,7 +341,7 @@ test_expect_success 'upload-pack respects config using protocol v2' '\n \tEOF\n \ttest_commit -C server one &&\n \n-\ttest_config_global uploadpack.packobjectshook ./hook &&\n+\ttest_config --global uploadpack.packobjectshook ./hook &&\n \ttest_path_is_missing server/.git/hookout &&\n \tgit -c protocol.version=2 clone \"file://$(pwd)/server\" client &&\n \ttest_path_is_file server/.git/hookout\ndiff --git a/t/t7814-grep-recurse-submodules.sh b/t/t7814-grep-recurse-submodules.sh\nindex a4476dc49220..36aa1f8a2afb 100755\n--- a/t/t7814-grep-recurse-submodules.sh\n+++ b/t/t7814-grep-recurse-submodules.sh\n@@ -444,7 +444,7 @@ test_expect_success 'grep --recurse-submodules with --cached ignores worktree mo\n \n test_expect_failure 'grep --textconv: superproject .gitattributes does not affect submodules' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \techo \"a diff=d2x\" >.gitattributes &&\n \n \tcat >expect <<-\\EOF &&\n@@ -456,7 +456,7 @@ test_expect_failure 'grep --textconv: superproject .gitattributes does not affec\n \n test_expect_failure 'grep --textconv: superproject .gitattributes (from index) does not affect submodules' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \techo \"a diff=d2x\" >.gitattributes &&\n \tgit add .gitattributes &&\n \trm .gitattributes &&\n@@ -470,7 +470,7 @@ test_expect_failure 'grep --textconv: superproject .gitattributes (from index) d\n \n test_expect_failure 'grep --textconv: superproject .git/info/attributes does not affect submodules' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \tsuper_attr=\"$(git rev-parse --git-path info/attributes)\" &&\n \ttest_when_finished \"rm -f \\\"$super_attr\\\"\" &&\n \techo \"a diff=d2x\" >\"$super_attr\" &&\n@@ -488,7 +488,7 @@ test_expect_failure 'grep --textconv: superproject .git/info/attributes does not\n #\n test_expect_failure 'grep --textconv correctly reads submodule .gitattributes' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \techo \"a diff=d2x\" >submodule/.gitattributes &&\n \n \tcat >expect <<-\\EOF &&\n@@ -500,7 +500,7 @@ test_expect_failure 'grep --textconv correctly reads submodule .gitattributes' '\n \n test_expect_failure 'grep --textconv correctly reads submodule .gitattributes (from index)' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \techo \"a diff=d2x\" >submodule/.gitattributes &&\n \tgit -C submodule add .gitattributes &&\n \trm submodule/.gitattributes &&\n@@ -514,7 +514,7 @@ test_expect_failure 'grep --textconv correctly reads submodule .gitattributes (f\n \n test_expect_failure 'grep --textconv correctly reads submodule .git/info/attributes' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n \n \tsubmodule_attr=\"$(git -C submodule rev-parse --path-format=absolute --git-path info/attributes)\" &&\n \ttest_when_finished \"rm -f \\\"$submodule_attr\\\"\" &&\n@@ -529,8 +529,8 @@ test_expect_failure 'grep --textconv correctly reads submodule .git/info/attribu\n \n test_expect_failure 'grep saves textconv cache in the appropriate repository' '\n \treset_and_clean &&\n-\ttest_config_global diff.d2x_cached.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n-\ttest_config_global diff.d2x_cached.cachetextconv true &&\n+\ttest_config --global diff.d2x_cached.textconv \"sed -e \\\"s/d/x/\\\"\" &&\n+\ttest_config --global diff.d2x_cached.cachetextconv true &&\n \techo \"a diff=d2x_cached\" >submodule/.gitattributes &&\n \n \t# We only read/write to the textconv cache when grepping from an OID,\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 6da7273f1d5f..e518b89bf128 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -506,16 +506,36 @@ test_modebits () {\n \t\t\t  -e 's|^\\(......\\)S|\\1-|' -e 's|^\\(......\\)s|\\1x|'\n }\n \n+# Usage: test_unconfig [options] <name>\n+#   -C <dir>:\n+#\tRun all git commits in directory <dir>\n+#   --global:\n+#\tModify the global configuration instead of repository.\n+#\n # Unset a configuration variable, but don't fail if it doesn't exist.\n test_unconfig () {\n+\tglobal=\n \tconfig_dir=\n-\tif test \"$1\" = -C\n-\tthen\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-C)\n+\t\t\tconfig_dir=\"$2\"\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--global)\n+\t\t\tglobal=--global\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tBUG \"invalid test_unconfig option: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n \t\tshift\n-\t\tconfig_dir=$1\n-\t\tshift\n-\tfi\n-\tgit ${config_dir:+-C \"$config_dir\"} config --unset-all \"$@\"\n+\tdone\n+\tgit ${config_dir:+-C \"$config_dir\"} config $global --unset-all \"$1\"\n \tconfig_status=$?\n \tcase \"$config_status\" in\n \t5) # ok, nothing to unset\n@@ -525,22 +545,38 @@ test_unconfig () {\n \treturn $config_status\n }\n \n+# Usage: test_config [options] <name> <value>\n+#   -C <dir>:\n+#\tRun all git commits in directory <dir>\n+#   --global:\n+#\tModify the global configuration instead of the repository\n+#\tconfiguration.\n+#\n # Set git config, automatically unsetting it after the test is over.\n test_config () {\n+\tglobal=\n \tconfig_dir=\n-\tif test \"$1\" = -C\n-\tthen\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t-C)\n+\t\t\tconfig_dir=\"$2\"\n+\t\t\tshift\n+\t\t\t;;\n+\t\t--global)\n+\t\t\tglobal=--global\n+\t\t\t;;\n+\t\t-*)\n+\t\t\tBUG \"invalid test_config option: $1\"\n+\t\t\t;;\n+\t\t*)\n+\t\t\tbreak\n+\t\t\t;;\n+\t\tesac\n \t\tshift\n-\t\tconfig_dir=$1\n-\t\tshift\n-\tfi\n-\ttest_when_finished \"test_unconfig ${config_dir:+-C '$config_dir'} '$1'\" &&\n-\tgit ${config_dir:+-C \"$config_dir\"} config \"$@\"\n-}\n-\n-test_config_global () {\n-\ttest_when_finished \"test_unconfig --global '$1'\" &&\n-\tgit config --global \"$@\"\n+\tdone\n+\ttest_when_finished \"test_unconfig ${config_dir:+-C '$config_dir'} $global '$1'\" &&\n+\tgit ${config_dir:+-C \"$config_dir\"} config $global \"$1\" \"$2\"\n }\n \n write_script () {\n-- \n2.36.1\n\n"},{"id":"457442","messageId":"20220617002036.1577-3-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 2/6] t5505: remove sub shell use in favor of git -C","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:32Z","receivedAt":"2022-06-17T00:20:50Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.e.keller@intel.com>\n\nThe t5505-remote.sh test script makes liberal use of sub shells to move\ndirectories before executing a series of git commands. This is not the\ntypical style of a more modern test script. Instead, newer tests favor\nthe use of git's \"-C\" option to change directory before executing.\n\nUpdate this test script to drop the unnecessary sub shells. Where\nnecessary, adjust the paths of various output files to account for this\nchange.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n t/t5505-remote.sh | 1061 ++++++++++++++++++---------------------------\n 1 file changed, 415 insertions(+), 646 deletions(-)\n\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 0aad0eb4d26c..c4228a27a71f 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -28,14 +28,28 @@ tokens_match () {\n }\n \n check_remote_track () {\n-\tactual=$(git remote show \"$1\" | sed -ne 's|^    \\(.*\\) tracked$|\\1|p')\n+\tlocal config_dir=\n+\tif test \"$1\" = -C\n+\tthen\n+\t\tshift\n+\t\tconfig_dir=$1\n+\t\tshift\n+\tfi\n+\tactual=$(git ${config_dir:+-C \"$config_dir\"} remote show \"$1\" | sed -ne 's|^    \\(.*\\) tracked$|\\1|p')\n \tshift &&\n \ttokens_match \"$*\" \"$actual\"\n }\n \n check_tracking_branch () {\n+\tlocal config_dir=\n+\tif test \"$1\" = -C\n+\tthen\n+\t\tshift\n+\t\tconfig_dir=$1\n+\t\tshift\n+\tfi\n \tf=\"\" &&\n-\tr=$(git for-each-ref \"--format=%(refname)\" |\n+\tr=$(git ${config_dir:+-C \"$config_dir\"} for-each-ref \"--format=%(refname)\" |\n \t\tsed -ne \"s|^refs/remotes/$1/||p\") &&\n \tshift &&\n \ttokens_match \"$*\" \"$r\"\n@@ -44,10 +58,7 @@ check_tracking_branch () {\n test_expect_success setup '\n \tsetup_repository one &&\n \tsetup_repository two &&\n-\t(\n-\t\tcd two &&\n-\t\tgit branch another\n-\t) &&\n+\tgit -C two branch another &&\n \tgit clone one test\n '\n \n@@ -57,25 +68,19 @@ test_expect_success 'add remote whose URL agrees with url.<...>.insteadOf' '\n '\n \n test_expect_success 'remote information for the origin' '\n-\t(\n-\t\tcd test &&\n-\t\ttokens_match origin \"$(git remote)\" &&\n-\t\tcheck_remote_track origin main side &&\n-\t\tcheck_tracking_branch origin HEAD main side\n-\t)\n+\ttokens_match origin \"$(git -C test remote)\" &&\n+\tcheck_remote_track -C test origin main side &&\n+\tcheck_tracking_branch -C test origin HEAD main side\n '\n \n test_expect_success 'add another remote' '\n-\t(\n-\t\tcd test &&\n-\t\tgit remote add -f second ../two &&\n-\t\ttokens_match \"origin second\" \"$(git remote)\" &&\n-\t\tcheck_tracking_branch second main side another &&\n-\t\tgit for-each-ref \"--format=%(refname)\" refs/remotes |\n-\t\tsed -e \"/^refs\\/remotes\\/origin\\//d\" \\\n-\t\t    -e \"/^refs\\/remotes\\/second\\//d\" >actual &&\n-\t\ttest_must_be_empty actual\n-\t)\n+\tgit -C test remote add -f second ../two &&\n+\ttokens_match \"origin second\" \"$(git -C test remote)\" &&\n+\tcheck_tracking_branch -C test second main side another &&\n+\tgit -C test for-each-ref \"--format=%(refname)\" refs/remotes |\n+\tsed -e \"/^refs\\/remotes\\/origin\\//d\" \\\n+\t\t-e \"/^refs\\/remotes\\/second\\//d\" >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'setup bare clone for server' '\n@@ -113,76 +118,58 @@ test_expect_success 'filters are listed by git remote -v only' '\n '\n \n test_expect_success 'check remote-tracking' '\n-\t(\n-\t\tcd test &&\n-\t\tcheck_remote_track origin main side &&\n-\t\tcheck_remote_track second main side another\n-\t)\n+\tcheck_remote_track -C test origin main side &&\n+\tcheck_remote_track -C test second main side another\n '\n \n test_expect_success 'remote forces tracking branches' '\n-\t(\n-\t\tcd test &&\n-\t\tcase $(git config remote.second.fetch) in\n-\t\t+*) true ;;\n-\t\t *) false ;;\n-\t\tesac\n-\t)\n+\tcase $(git -C test config remote.second.fetch) in\n+\t+*) true ;;\n+\t *) false ;;\n+\tesac\n '\n \n test_expect_success 'remove remote' '\n-\t(\n-\t\tcd test &&\n-\t\tgit symbolic-ref refs/remotes/second/HEAD refs/remotes/second/main &&\n-\t\tgit remote rm second\n-\t)\n+\tgit -C test symbolic-ref refs/remotes/second/HEAD refs/remotes/second/main &&\n+\tgit -C test remote rm second\n '\n \n test_expect_success 'remove remote' '\n-\t(\n-\t\tcd test &&\n-\t\ttokens_match origin \"$(git remote)\" &&\n-\t\tcheck_remote_track origin main side &&\n-\t\tgit for-each-ref \"--format=%(refname)\" refs/remotes |\n-\t\tsed -e \"/^refs\\/remotes\\/origin\\//d\" >actual &&\n-\t\ttest_must_be_empty actual\n-\t)\n+\ttokens_match origin \"$(git -C test remote)\" &&\n+\tcheck_remote_track -C test origin main side &&\n+\tgit -C test for-each-ref \"--format=%(refname)\" refs/remotes |\n+\tsed -e \"/^refs\\/remotes\\/origin\\//d\" >actual &&\n+\ttest_must_be_empty actual\n '\n \n test_expect_success 'remove remote protects local branches' '\n-\t(\n-\t\tcd test &&\n-\t\tcat >expect1 <<-\\EOF &&\n-\t\tNote: A branch outside the refs/remotes/ hierarchy was not removed;\n-\t\tto delete it, use:\n-\t\t  git branch -d main\n-\t\tEOF\n-\t\tcat >expect2 <<-\\EOF &&\n-\t\tNote: Some branches outside the refs/remotes/ hierarchy were not removed;\n-\t\tto delete them, use:\n-\t\t  git branch -d foobranch\n-\t\t  git branch -d main\n-\t\tEOF\n-\t\tgit tag footag &&\n-\t\tgit config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n-\t\tgit remote remove oops 2>actual1 &&\n-\t\tgit branch foobranch &&\n-\t\tgit config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n-\t\tgit remote rm oops 2>actual2 &&\n-\t\tgit branch -d foobranch &&\n-\t\tgit tag -d footag &&\n-\t\ttest_cmp expect1 actual1 &&\n-\t\ttest_cmp expect2 actual2\n-\t)\n+\tcat >expect1 <<-\\EOF &&\n+\tNote: A branch outside the refs/remotes/ hierarchy was not removed;\n+\tto delete it, use:\n+\t  git branch -d main\n+\tEOF\n+\tcat >expect2 <<-\\EOF &&\n+\tNote: Some branches outside the refs/remotes/ hierarchy were not removed;\n+\tto delete them, use:\n+\t  git branch -d foobranch\n+\t  git branch -d main\n+\tEOF\n+\tgit -C test tag footag &&\n+\tgit -C test config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n+\tgit -C test remote remove oops 2>actual1 &&\n+\tgit -C test branch foobranch &&\n+\tgit -C test config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n+\tgit -C test remote rm oops 2>actual2 &&\n+\tgit -C test branch -d foobranch &&\n+\tgit -C test tag -d footag &&\n+\ttest_cmp expect1 actual1 &&\n+\ttest_cmp expect2 actual2\n '\n \n test_expect_success 'remove errors out early when deleting non-existent branch' '\n-\t(\n-\t\tcd test &&\n-\t\techo \"error: No such remote: '\\''foo'\\''\" >expect &&\n-\t\ttest_expect_code 2 git remote rm foo 2>actual &&\n-\t\ttest_cmp expect actual\n-\t)\n+\techo \"error: No such remote: '\\''foo'\\''\" >expect &&\n+\ttest_expect_code 2 git -C test remote rm foo 2>actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'remove remote with a branch without configured merge' '\n@@ -193,24 +180,18 @@ test_expect_success 'remove remote with a branch without configured merge' '\n \t\tgit -C test config --remove-section branch.second;\n \t\ttrue\n \t)\" &&\n-\t(\n-\t\tcd test &&\n-\t\tgit remote add two ../two &&\n-\t\tgit fetch two &&\n-\t\tgit checkout -b second two/main^0 &&\n-\t\tgit config branch.second.remote two &&\n-\t\tgit checkout main &&\n-\t\tgit remote rm two\n-\t)\n+\tgit -C test remote add two ../two &&\n+\tgit -C test fetch two &&\n+\tgit -C test checkout -b second two/main^0 &&\n+\tgit -C test config branch.second.remote two &&\n+\tgit -C test checkout main &&\n+\tgit -C test remote rm two\n '\n \n test_expect_success 'rename errors out early when deleting non-existent branch' '\n-\t(\n-\t\tcd test &&\n-\t\techo \"error: No such remote: '\\''foo'\\''\" >expect &&\n-\t\ttest_expect_code 2 git remote rename foo bar 2>actual &&\n-\t\ttest_cmp expect actual\n-\t)\n+\techo \"error: No such remote: '\\''foo'\\''\" >expect &&\n+\ttest_expect_code 2 git -C test remote rename foo bar 2>actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'rename errors out early when new name is invalid' '\n@@ -241,7 +222,7 @@ test_expect_success 'add invalid foreign_vcs remote' '\n \ttest_cmp expect actual\n '\n \n-cat >test/expect <<EOF\n+cat >expect <<EOF\n * remote origin\n   Fetch URL: $(pwd)/one\n   Push  URL: $(pwd)/one\n@@ -269,37 +250,31 @@ cat >test/expect <<EOF\n EOF\n \n test_expect_success 'show' '\n-\t(\n-\t\tcd test &&\n-\t\tgit config --add remote.origin.fetch refs/heads/main:refs/heads/upstream &&\n-\t\tgit fetch &&\n-\t\tgit checkout -b ahead origin/main &&\n-\t\techo 1 >>file &&\n-\t\ttest_tick &&\n-\t\tgit commit -m update file &&\n-\t\tgit checkout main &&\n-\t\tgit branch --track octopus origin/main &&\n-\t\tgit branch --track rebase origin/main &&\n-\t\tgit branch -d -r origin/main &&\n-\t\tgit config --add remote.two.url ../two &&\n-\t\tgit config --add remote.two.pushurl ../three &&\n-\t\tgit config branch.rebase.rebase true &&\n-\t\tgit config branch.octopus.merge \"topic-a topic-b topic-c\" &&\n-\t\t(\n-\t\t\tcd ../one &&\n-\t\t\techo 1 >file &&\n-\t\t\ttest_tick &&\n-\t\t\tgit commit -m update file\n-\t\t) &&\n-\t\tgit config --add remote.origin.push : &&\n-\t\tgit config --add remote.origin.push refs/heads/main:refs/heads/upstream &&\n-\t\tgit config --add remote.origin.push +refs/tags/lastbackup &&\n-\t\tgit config --add remote.two.push +refs/heads/ahead:refs/heads/main &&\n-\t\tgit config --add remote.two.push refs/heads/main:refs/heads/another &&\n-\t\tgit remote show origin two >output &&\n-\t\tgit branch -d rebase octopus &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test config --add remote.origin.fetch refs/heads/main:refs/heads/upstream &&\n+\tgit -C test fetch &&\n+\tgit -C test checkout -b ahead origin/main &&\n+\techo 1 >>test/file &&\n+\ttest_tick &&\n+\tgit -C test commit -m update file &&\n+\tgit -C test checkout main &&\n+\tgit -C test branch --track octopus origin/main &&\n+\tgit -C test branch --track rebase origin/main &&\n+\tgit -C test branch -d -r origin/main &&\n+\tgit -C test config --add remote.two.url ../two &&\n+\tgit -C test config --add remote.two.pushurl ../three &&\n+\tgit -C test config branch.rebase.rebase true &&\n+\tgit -C test config branch.octopus.merge \"topic-a topic-b topic-c\" &&\n+\techo 1 >one/file &&\n+\ttest_tick &&\n+\tgit -C one commit -m update file &&\n+\tgit -C test config --add remote.origin.push : &&\n+\tgit -C test config --add remote.origin.push refs/heads/main:refs/heads/upstream &&\n+\tgit -C test config --add remote.origin.push +refs/tags/lastbackup &&\n+\tgit -C test config --add remote.two.push +refs/heads/ahead:refs/heads/main &&\n+\tgit -C test config --add remote.two.push refs/heads/main:refs/heads/another &&\n+\tgit -C test remote show origin two >output &&\n+\tgit -C test branch -d rebase octopus &&\n+\ttest_cmp expect output\n '\n \n cat >expect <<EOF\n@@ -348,7 +323,7 @@ test_expect_failure 'show stale with negative refspecs' '\n \ttest_cmp expect output\n '\n \n-cat >test/expect <<EOF\n+cat >expect <<EOF\n * remote origin\n   Fetch URL: $(pwd)/one\n   Push  URL: $(pwd)/one\n@@ -367,72 +342,51 @@ EOF\n \n test_expect_success 'show -n' '\n \tmv one one.unreachable &&\n-\t(\n-\t\tcd test &&\n-\t\tgit remote show -n origin >output &&\n-\t\tmv ../one.unreachable ../one &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test remote show -n origin >output &&\n+\tmv one.unreachable one &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'prune' '\n-\t(\n-\t\tcd one &&\n-\t\tgit branch -m side side2\n-\t) &&\n-\t(\n-\t\tcd test &&\n-\t\tgit fetch origin &&\n-\t\tgit remote prune origin &&\n-\t\tgit rev-parse refs/remotes/origin/side2 &&\n-\t\ttest_must_fail git rev-parse refs/remotes/origin/side\n-\t)\n+\tgit -C one branch -m side side2 &&\n+\tgit -C test fetch origin &&\n+\tgit -C test remote prune origin &&\n+\tgit -C test rev-parse refs/remotes/origin/side2 &&\n+\ttest_must_fail git -C test rev-parse refs/remotes/origin/side\n '\n \n test_expect_success 'set-head --delete' '\n-\t(\n-\t\tcd test &&\n-\t\tgit symbolic-ref refs/remotes/origin/HEAD &&\n-\t\tgit remote set-head --delete origin &&\n-\t\ttest_must_fail git symbolic-ref refs/remotes/origin/HEAD\n-\t)\n+\tgit -C test symbolic-ref refs/remotes/origin/HEAD &&\n+\tgit -C test remote set-head --delete origin &&\n+\ttest_must_fail git -C test symbolic-ref refs/remotes/origin/HEAD\n '\n \n test_expect_success 'set-head --auto' '\n-\t(\n-\t\tcd test &&\n-\t\tgit remote set-head --auto origin &&\n-\t\techo refs/remotes/origin/main >expect &&\n-\t\tgit symbolic-ref refs/remotes/origin/HEAD >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test remote set-head --auto origin &&\n+\techo refs/remotes/origin/main >expect &&\n+\tgit -C test symbolic-ref refs/remotes/origin/HEAD >output &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'set-head --auto has no problem w/multiple HEADs' '\n-\t(\n-\t\tcd test &&\n-\t\tgit fetch two \"refs/heads/*:refs/remotes/two/*\" &&\n-\t\tgit remote set-head --auto two >output 2>&1 &&\n-\t\techo \"two/HEAD set to main\" >expect &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test fetch two \"refs/heads/*:refs/remotes/two/*\" &&\n+\tgit -C test remote set-head --auto two >output 2>&1 &&\n+\techo \"two/HEAD set to main\" >expect &&\n+\ttest_cmp expect output\n '\n \n-cat >test/expect <<\\EOF\n+cat >expect <<\\EOF\n refs/remotes/origin/side2\n EOF\n \n test_expect_success 'set-head explicit' '\n-\t(\n-\t\tcd test &&\n-\t\tgit remote set-head origin side2 &&\n-\t\tgit symbolic-ref refs/remotes/origin/HEAD >output &&\n-\t\tgit remote set-head origin main &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test remote set-head origin side2 &&\n+\tgit -C test symbolic-ref refs/remotes/origin/HEAD >output &&\n+\tgit -C test remote set-head origin main &&\n+\ttest_cmp expect output\n '\n \n-cat >test/expect <<EOF\n+cat >expect <<EOF\n Pruning origin\n URL: $(pwd)/one\n  * [would prune] origin/side2\n@@ -441,206 +395,131 @@ EOF\n test_expect_success 'prune --dry-run' '\n \tgit -C one branch -m side2 side &&\n \ttest_when_finished \"git -C one branch -m side side2\" &&\n-\t(\n-\t\tcd test &&\n-\t\tgit remote prune --dry-run origin >output &&\n-\t\tgit rev-parse refs/remotes/origin/side2 &&\n-\t\ttest_must_fail git rev-parse refs/remotes/origin/side &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C test remote prune --dry-run origin >output &&\n+\tgit -C test rev-parse refs/remotes/origin/side2 &&\n+\ttest_must_fail git -C test rev-parse refs/remotes/origin/side &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'add --mirror && prune' '\n \tmkdir mirror &&\n-\t(\n-\t\tcd mirror &&\n-\t\tgit init --bare &&\n-\t\tgit remote add --mirror -f origin ../one\n-\t) &&\n-\t(\n-\t\tcd one &&\n-\t\tgit branch -m side2 side\n-\t) &&\n-\t(\n-\t\tcd mirror &&\n-\t\tgit rev-parse --verify refs/heads/side2 &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/side &&\n-\t\tgit fetch origin &&\n-\t\tgit remote prune origin &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/side2 &&\n-\t\tgit rev-parse --verify refs/heads/side\n-\t)\n+\tgit -C mirror init --bare &&\n+\tgit -C mirror remote add --mirror -f origin ../one &&\n+\tgit -C one branch -m side2 side &&\n+\tgit -C mirror rev-parse --verify refs/heads/side2 &&\n+\ttest_must_fail git -C mirror rev-parse --verify refs/heads/side &&\n+\tgit -C mirror fetch origin &&\n+\tgit -C mirror remote prune origin &&\n+\ttest_must_fail git -C mirror rev-parse --verify refs/heads/side2 &&\n+\tgit -C mirror rev-parse --verify refs/heads/side\n '\n \n test_expect_success 'add --mirror=fetch' '\n \tmkdir mirror-fetch &&\n \tgit init -b main mirror-fetch/parent &&\n-\t(\n-\t\tcd mirror-fetch/parent &&\n-\t\ttest_commit one\n-\t) &&\n+\ttest_commit -C mirror-fetch/parent one &&\n \tgit init --bare mirror-fetch/child &&\n-\t(\n-\t\tcd mirror-fetch/child &&\n-\t\tgit remote add --mirror=fetch -f parent ../parent\n-\t)\n+\tgit -C mirror-fetch/child remote add --mirror=fetch -f parent ../parent\n '\n \n test_expect_success 'fetch mirrors act as mirrors during fetch' '\n-\t(\n-\t\tcd mirror-fetch/parent &&\n-\t\tgit branch new &&\n-\t\tgit branch -m main renamed\n-\t) &&\n-\t(\n-\t\tcd mirror-fetch/child &&\n-\t\tgit fetch parent &&\n-\t\tgit rev-parse --verify refs/heads/new &&\n-\t\tgit rev-parse --verify refs/heads/renamed\n-\t)\n+\tgit -C mirror-fetch/parent branch new &&\n+\tgit -C mirror-fetch/parent branch -m main renamed &&\n+\tgit -C mirror-fetch/child fetch parent &&\n+\tgit -C mirror-fetch/child rev-parse --verify refs/heads/new &&\n+\tgit -C mirror-fetch/child rev-parse --verify refs/heads/renamed\n '\n \n test_expect_success 'fetch mirrors can prune' '\n-\t(\n-\t\tcd mirror-fetch/child &&\n-\t\tgit remote prune parent &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/main\n-\t)\n+\tgit -C mirror-fetch/child remote prune parent &&\n+\ttest_must_fail git -C mirror-fetch/child rev-parse --verify refs/heads/main\n '\n \n test_expect_success 'fetch mirrors do not act as mirrors during push' '\n-\t(\n-\t\tcd mirror-fetch/parent &&\n-\t\tgit checkout HEAD^0\n-\t) &&\n-\t(\n-\t\tcd mirror-fetch/child &&\n-\t\tgit branch -m renamed renamed2 &&\n-\t\tgit push parent :\n-\t) &&\n-\t(\n-\t\tcd mirror-fetch/parent &&\n-\t\tgit rev-parse --verify renamed &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/renamed2\n-\t)\n+\tgit -C mirror-fetch/parent checkout HEAD^0 &&\n+\tgit -C mirror-fetch/child branch -m renamed renamed2 &&\n+\tgit -C mirror-fetch/child push parent : &&\n+\tgit -C mirror-fetch/parent rev-parse --verify renamed &&\n+\ttest_must_fail git -C mirror-fetch/parent rev-parse --verify refs/heads/renamed2\n '\n \n test_expect_success 'add fetch mirror with specific branches' '\n \tgit init --bare mirror-fetch/track &&\n-\t(\n-\t\tcd mirror-fetch/track &&\n-\t\tgit remote add --mirror=fetch -t heads/new parent ../parent\n-\t)\n+\tgit -C mirror-fetch/track remote add --mirror=fetch -t heads/new parent ../parent\n '\n \n test_expect_success 'fetch mirror respects specific branches' '\n-\t(\n-\t\tcd mirror-fetch/track &&\n-\t\tgit fetch parent &&\n-\t\tgit rev-parse --verify refs/heads/new &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/renamed\n-\t)\n+\tgit -C mirror-fetch/track fetch parent &&\n+\tgit -C mirror-fetch/track rev-parse --verify refs/heads/new &&\n+\ttest_must_fail git -C mirror-fetch/track rev-parse --verify refs/heads/renamed\n '\n \n test_expect_success 'add --mirror=push' '\n \tmkdir mirror-push &&\n \tgit init --bare mirror-push/public &&\n \tgit init -b main mirror-push/private &&\n-\t(\n-\t\tcd mirror-push/private &&\n-\t\ttest_commit one &&\n-\t\tgit remote add --mirror=push public ../public\n-\t)\n+\ttest_commit -C mirror-push/private one &&\n+\tgit -C mirror-push/private remote add --mirror=push public ../public\n '\n \n test_expect_success 'push mirrors act as mirrors during push' '\n-\t(\n-\t\tcd mirror-push/private &&\n-\t\tgit branch new &&\n-\t\tgit branch -m main renamed &&\n-\t\tgit push public\n-\t) &&\n-\t(\n-\t\tcd mirror-push/private &&\n-\t\tgit rev-parse --verify refs/heads/new &&\n-\t\tgit rev-parse --verify refs/heads/renamed &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/main\n-\t)\n+\tgit -C mirror-push/private branch new &&\n+\tgit -C mirror-push/private branch -m main renamed &&\n+\tgit -C mirror-push/private push public &&\n+\tgit -C mirror-push/private rev-parse --verify refs/heads/new &&\n+\tgit -C mirror-push/private rev-parse --verify refs/heads/renamed &&\n+\ttest_must_fail git -C mirror-push/private rev-parse --verify refs/heads/main\n '\n \n test_expect_success 'push mirrors do not act as mirrors during fetch' '\n-\t(\n-\t\tcd mirror-push/public &&\n-\t\tgit branch -m renamed renamed2 &&\n-\t\tgit symbolic-ref HEAD refs/heads/renamed2\n-\t) &&\n-\t(\n-\t\tcd mirror-push/private &&\n-\t\tgit fetch public &&\n-\t\tgit rev-parse --verify refs/heads/renamed &&\n-\t\ttest_must_fail git rev-parse --verify refs/heads/renamed2\n-\t)\n+\tgit -C mirror-push/public branch -m renamed renamed2 &&\n+\tgit -C mirror-push/public symbolic-ref HEAD refs/heads/renamed2 &&\n+\tgit -C mirror-push/private fetch public &&\n+\tgit -C mirror-push/private rev-parse --verify refs/heads/renamed &&\n+\ttest_must_fail git -C mirror-push/private rev-parse --verify refs/heads/renamed2\n '\n \n test_expect_success 'push mirrors do not allow you to specify refs' '\n \tgit init mirror-push/track &&\n-\t(\n-\t\tcd mirror-push/track &&\n-\t\ttest_must_fail git remote add --mirror=push -t new public ../public\n-\t)\n+\ttest_must_fail git -C mirror-push/track remote add --mirror=push -t new public ../public\n '\n \n test_expect_success 'add alt && prune' '\n \tmkdir alttst &&\n-\t(\n-\t\tcd alttst &&\n-\t\tgit init &&\n-\t\tgit remote add -f origin ../one &&\n-\t\tgit config remote.alt.url ../one &&\n-\t\tgit config remote.alt.fetch \"+refs/heads/*:refs/remotes/origin/*\"\n-\t) &&\n-\t(\n-\t\tcd one &&\n-\t\tgit branch -m side side2\n-\t) &&\n-\t(\n-\t\tcd alttst &&\n-\t\tgit rev-parse --verify refs/remotes/origin/side &&\n-\t\ttest_must_fail git rev-parse --verify refs/remotes/origin/side2 &&\n-\t\tgit fetch alt &&\n-\t\tgit remote prune alt &&\n-\t\ttest_must_fail git rev-parse --verify refs/remotes/origin/side &&\n-\t\tgit rev-parse --verify refs/remotes/origin/side2\n-\t)\n+\tgit -C alttst init &&\n+\tgit -C alttst remote add -f origin ../one &&\n+\tgit -C alttst config remote.alt.url ../one &&\n+\tgit -C alttst config remote.alt.fetch \"+refs/heads/*:refs/remotes/origin/*\" &&\n+\tgit -C one branch -m side side2 &&\n+\tgit -C alttst rev-parse --verify refs/remotes/origin/side &&\n+\ttest_must_fail git -C alttst rev-parse --verify refs/remotes/origin/side2 &&\n+\tgit -C alttst fetch alt &&\n+\tgit -C alttst remote prune alt &&\n+\ttest_must_fail git -C alttst rev-parse --verify refs/remotes/origin/side &&\n+\tgit -C alttst rev-parse --verify refs/remotes/origin/side2\n '\n \n-cat >test/expect <<\\EOF\n+cat >expect <<\\EOF\n some-tag\n EOF\n \n test_expect_success 'add with reachable tags (default)' '\n-\t(\n-\t\tcd one &&\n-\t\t>foobar &&\n-\t\tgit add foobar &&\n-\t\tgit commit -m \"Foobar\" &&\n-\t\tgit tag -a -m \"Foobar tag\" foobar-tag &&\n-\t\tgit reset --hard HEAD~1 &&\n-\t\tgit tag -a -m \"Some tag\" some-tag\n-\t) &&\n+\t>one/foobar &&\n+\tgit -C one add foobar &&\n+\tgit -C one commit -m \"Foobar\" &&\n+\tgit -C one tag -a -m \"Foobar tag\" foobar-tag &&\n+\tgit -C one reset --hard HEAD~1 &&\n+\tgit -C one tag -a -m \"Some tag\" some-tag &&\n \tmkdir add-tags &&\n-\t(\n-\t\tcd add-tags &&\n-\t\tgit init &&\n-\t\tgit remote add -f origin ../one &&\n-\t\tgit tag -l some-tag >../test/output &&\n-\t\tgit tag -l foobar-tag >>../test/output &&\n-\t\ttest_must_fail git config remote.origin.tagopt\n-\t) &&\n-\ttest_cmp test/expect test/output\n+\tgit -C add-tags init &&\n+\tgit -C add-tags remote add -f origin ../one &&\n+\tgit -C add-tags tag -l some-tag >output &&\n+\tgit -C add-tags tag -l foobar-tag >>output &&\n+\ttest_must_fail git -C add-tags config remote.origin.tagopt &&\n+\ttest_cmp expect output\n '\n \n-cat >test/expect <<\\EOF\n+cat >expect <<\\EOF\n some-tag\n foobar-tag\n --tags\n@@ -648,49 +527,37 @@ EOF\n \n test_expect_success 'add --tags' '\n \trm -rf add-tags &&\n-\t(\n-\t\tmkdir add-tags &&\n-\t\tcd add-tags &&\n-\t\tgit init &&\n-\t\tgit remote add -f --tags origin ../one &&\n-\t\tgit tag -l some-tag >../test/output &&\n-\t\tgit tag -l foobar-tag >>../test/output &&\n-\t\tgit config remote.origin.tagopt >>../test/output\n-\t) &&\n-\ttest_cmp test/expect test/output\n+\tmkdir add-tags &&\n+\tgit -C add-tags init &&\n+\tgit -C add-tags remote add -f --tags origin ../one &&\n+\tgit -C add-tags tag -l some-tag >output &&\n+\tgit -C add-tags tag -l foobar-tag >>output &&\n+\tgit -C add-tags config remote.origin.tagopt >>output &&\n+\ttest_cmp expect output\n '\n \n-cat >test/expect <<\\EOF\n+cat >expect <<\\EOF\n --no-tags\n EOF\n \n test_expect_success 'add --no-tags' '\n \trm -rf add-tags &&\n-\t(\n-\t\tmkdir add-no-tags &&\n-\t\tcd add-no-tags &&\n-\t\tgit init &&\n-\t\tgit remote add -f --no-tags origin ../one &&\n-\t\tgrep tagOpt .git/config &&\n-\t\tgit tag -l some-tag >../test/output &&\n-\t\tgit tag -l foobar-tag >../test/output &&\n-\t\tgit config remote.origin.tagopt >>../test/output\n-\t) &&\n-\t(\n-\t\tcd one &&\n-\t\tgit tag -d some-tag foobar-tag\n-\t) &&\n-\ttest_cmp test/expect test/output\n+\tmkdir add-no-tags &&\n+\tgit -C add-no-tags init &&\n+\tgit -C add-no-tags remote add -f --no-tags origin ../one &&\n+\tgrep tagOpt add-no-tags/.git/config &&\n+\tgit -C add-no-tags tag -l some-tag >output &&\n+\tgit -C add-no-tags tag -l foobar-tag >output &&\n+\tgit -C add-no-tags config remote.origin.tagopt >>output &&\n+\tgit -C one tag -d some-tag foobar-tag &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'reject --no-no-tags' '\n-\t(\n-\t\tcd add-no-tags &&\n-\t\ttest_must_fail git remote add -f --no-no-tags neworigin ../one\n-\t)\n+\ttest_must_fail git -C add-no-tags remote add -f --no-no-tags neworigin ../one\n '\n \n-cat >one/expect <<\\EOF\n+cat >expect <<\\EOF\n   apis/main\n   apis/side\n   drosophila/another\n@@ -699,17 +566,14 @@ cat >one/expect <<\\EOF\n EOF\n \n test_expect_success 'update' '\n-\t(\n-\t\tcd one &&\n-\t\tgit remote add drosophila ../two &&\n-\t\tgit remote add apis ../mirror &&\n-\t\tgit remote update &&\n-\t\tgit branch -r >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tgit -C one remote add drosophila ../two &&\n+\tgit -C one remote add apis ../mirror &&\n+\tgit -C one remote update &&\n+\tgit -C one branch -r >output &&\n+\ttest_cmp expect output\n '\n \n-cat >one/expect <<\\EOF\n+cat >expect <<\\EOF\n   drosophila/another\n   drosophila/main\n   drosophila/side\n@@ -720,40 +584,28 @@ cat >one/expect <<\\EOF\n EOF\n \n test_expect_success 'update with arguments' '\n-\t(\n-\t\tcd one &&\n-\t\tfor b in $(git branch -r)\n-\t\tdo\n-\t\tgit branch -r -d $b || exit 1\n-\t\tdone &&\n-\t\tgit remote add manduca ../mirror &&\n-\t\tgit remote add megaloprepus ../mirror &&\n-\t\tgit config remotes.phobaeticus \"drosophila megaloprepus\" &&\n-\t\tgit config remotes.titanus manduca &&\n-\t\tgit remote update phobaeticus titanus &&\n-\t\tgit branch -r >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tfor b in $(git -C one branch -r)\n+\tdo\n+\tgit -C one branch -r -d $b || exit 1\n+\tdone &&\n+\tgit -C one remote add manduca ../mirror &&\n+\tgit -C one remote add megaloprepus ../mirror &&\n+\tgit -C one config remotes.phobaeticus \"drosophila megaloprepus\" &&\n+\tgit -C one config remotes.titanus manduca &&\n+\tgit -C one remote update phobaeticus titanus &&\n+\tgit -C one branch -r >output &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'update --prune' '\n-\t(\n-\t\tcd one &&\n-\t\tgit branch -m side2 side3\n-\t) &&\n-\t(\n-\t\tcd test &&\n-\t\tgit remote update --prune &&\n-\t\t(\n-\t\t\tcd ../one &&\n-\t\t\tgit branch -m side3 side2\n-\t\t) &&\n-\t\tgit rev-parse refs/remotes/origin/side3 &&\n-\t\ttest_must_fail git rev-parse refs/remotes/origin/side2\n-\t)\n+\tgit -C one branch -m side2 side3 &&\n+\tgit -C test remote update --prune &&\n+\tgit -C one branch -m side3 side2 &&\n+\tgit -C test rev-parse refs/remotes/origin/side3 &&\n+\ttest_must_fail git -C test rev-parse refs/remotes/origin/side2\n '\n \n-cat >one/expect <<-\\EOF\n+cat >expect <<-\\EOF\n   apis/main\n   apis/side\n   manduca/main\n@@ -763,61 +615,49 @@ cat >one/expect <<-\\EOF\n EOF\n \n test_expect_success 'update default' '\n-\t(\n-\t\tcd one &&\n-\t\tfor b in $(git branch -r)\n-\t\tdo\n-\t\tgit branch -r -d $b || exit 1\n-\t\tdone &&\n-\t\tgit config remote.drosophila.skipDefaultUpdate true &&\n-\t\tgit remote update default &&\n-\t\tgit branch -r >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tfor b in $(git -C one branch -r)\n+\tdo\n+\tgit -C one branch -r -d $b || exit 1\n+\tdone &&\n+\tgit -C one config remote.drosophila.skipDefaultUpdate true &&\n+\tgit -C one remote update default &&\n+\tgit -C one branch -r >output &&\n+\ttest_cmp expect output\n '\n \n-cat >one/expect <<\\EOF\n+cat >expect <<\\EOF\n   drosophila/another\n   drosophila/main\n   drosophila/side\n EOF\n \n test_expect_success 'update default (overridden, with funny whitespace)' '\n-\t(\n-\t\tcd one &&\n-\t\tfor b in $(git branch -r)\n-\t\tdo\n-\t\tgit branch -r -d $b || exit 1\n-\t\tdone &&\n-\t\tgit config remotes.default \"$(printf \"\\t drosophila  \\n\")\" &&\n-\t\tgit remote update default &&\n-\t\tgit branch -r >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tfor b in $(git -C one branch -r)\n+\tdo\n+\tgit -C one branch -r -d $b || exit 1\n+\tdone &&\n+\tgit -C one config remotes.default \"$(printf \"\\t drosophila  \\n\")\" &&\n+\tgit -C one remote update default &&\n+\tgit -C one branch -r >output &&\n+\ttest_cmp expect output\n '\n \n test_expect_success 'update (with remotes.default defined)' '\n-\t(\n-\t\tcd one &&\n-\t\tfor b in $(git branch -r)\n-\t\tdo\n-\t\tgit branch -r -d $b || exit 1\n-\t\tdone &&\n-\t\tgit config remotes.default \"drosophila\" &&\n-\t\tgit remote update &&\n-\t\tgit branch -r >output &&\n-\t\ttest_cmp expect output\n-\t)\n+\tfor b in $(git -C one branch -r)\n+\tdo\n+\tgit -C one branch -r -d $b || exit 1\n+\tdone &&\n+\tgit -C one config remotes.default \"drosophila\" &&\n+\tgit -C one remote update &&\n+\tgit -C one branch -r >output &&\n+\ttest_cmp expect output\n '\n \n test_expect_success '\"remote show\" does not show symbolic refs' '\n \tgit clone one three &&\n-\t(\n-\t\tcd three &&\n-\t\tgit remote show origin >output &&\n-\t\t! grep \"^ *HEAD$\" < output &&\n-\t\t! grep -i stale < output\n-\t)\n+\tgit -C three remote show origin >output &&\n+\t! grep \"^ *HEAD$\" < output &&\n+\t! grep -i stale < output\n '\n \n test_expect_success 'reject adding remote with an invalid name' '\n@@ -830,87 +670,66 @@ test_expect_success 'reject adding remote with an invalid name' '\n test_expect_success 'rename a remote' '\n \ttest_config_global remote.pushDefault origin &&\n \tgit clone one four &&\n-\t(\n-\t\tcd four &&\n-\t\tgit config branch.main.pushRemote origin &&\n-\t\tGIT_TRACE2_EVENT=$(pwd)/trace \\\n-\t\t\tgit remote rename --progress origin upstream &&\n-\t\ttest_region progress \"Renaming remote references\" trace &&\n-\t\tgrep \"pushRemote\" .git/config &&\n-\t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n-\t\ttest \"$(git symbolic-ref refs/remotes/upstream/HEAD)\" = \"refs/remotes/upstream/main\" &&\n-\t\ttest \"$(git rev-parse upstream/main)\" = \"$(git rev-parse main)\" &&\n-\t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\" &&\n-\t\ttest \"$(git config branch.main.remote)\" = \"upstream\" &&\n-\t\ttest \"$(git config branch.main.pushRemote)\" = \"upstream\" &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n-\t)\n+\tgit -C four config branch.main.pushRemote origin &&\n+\tGIT_TRACE2_EVENT=$(pwd)/trace \\\n+\t\tgit -C four remote rename --progress origin upstream &&\n+\ttest_region progress \"Renaming remote references\" trace &&\n+\tgrep \"pushRemote\" four/.git/config &&\n+\ttest -z \"$(git -C four for-each-ref refs/remotes/origin)\" &&\n+\ttest \"$(git -C four symbolic-ref refs/remotes/upstream/HEAD)\" = \"refs/remotes/upstream/main\" &&\n+\ttest \"$(git -C four rev-parse upstream/main)\" = \"$(git -C four rev-parse main)\" &&\n+\ttest \"$(git -C four config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\" &&\n+\ttest \"$(git -C four config branch.main.remote)\" = \"upstream\" &&\n+\ttest \"$(git -C four config branch.main.pushRemote)\" = \"upstream\" &&\n+\ttest \"$(git -C four config --global remote.pushDefault)\" = \"origin\"\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault' '\n \tgit clone one four.1 &&\n-\t(\n-\t\tcd four.1 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote rename origin upstream &&\n-\t\tgrep pushDefault .git/config &&\n-\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n-\t)\n+\tgit -C four.1 config remote.pushDefault origin &&\n+\tgit -C four.1 remote rename origin upstream &&\n+\tgrep pushDefault four.1/.git/config &&\n+\ttest \"$(git -C four.1 config --local remote.pushDefault)\" = \"upstream\"\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n \ttest_config_global remote.pushDefault other &&\n \tgit clone one four.2 &&\n-\t(\n-\t\tcd four.2 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote rename origin upstream &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n-\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n-\t)\n+\tgit -C four.2 config remote.pushDefault origin &&\n+\tgit -C four.2 remote rename origin upstream &&\n+\ttest \"$(git -C four.2 config --global remote.pushDefault)\" = \"other\" &&\n+\ttest \"$(git -C four.2 config --local remote.pushDefault)\" = \"upstream\"\n '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n \ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.3 &&\n-\t(\n-\t\tcd four.3 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote rename origin upstream &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n-\t\ttest \"$(git config --local remote.pushDefault)\" = \"upstream\"\n-\t)\n+\tgit -C four.3 config remote.pushDefault origin &&\n+\tgit -C four.3 remote rename origin upstream &&\n+\ttest \"$(git -C four.3 config --global remote.pushDefault)\" = \"origin\" &&\n+\ttest \"$(git -C four.3 config --local remote.pushDefault)\" = \"upstream\"\n '\n \n test_expect_success 'rename does not update a non-default fetch refspec' '\n \tgit clone one four.one &&\n-\t(\n-\t\tcd four.one &&\n-\t\tgit config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&\n-\t\tgit remote rename origin upstream &&\n-\t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/heads/origin/*\" &&\n-\t\tgit rev-parse -q origin/main\n-\t)\n+\tgit -C four.one config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&\n+\tgit -C four.one remote rename origin upstream &&\n+\ttest \"$(git -C four.one config remote.upstream.fetch)\" = \"+refs/heads/*:refs/heads/origin/*\" &&\n+\tgit -C four.one rev-parse -q origin/main\n '\n \n test_expect_success 'rename a remote with name part of fetch spec' '\n \tgit clone one four.two &&\n-\t(\n-\t\tcd four.two &&\n-\t\tgit remote rename origin remote &&\n-\t\tgit remote rename remote upstream &&\n-\t\ttest \"$(git config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\"\n-\t)\n+\tgit -C four.two remote rename origin remote &&\n+\tgit -C four.two remote rename remote upstream &&\n+\ttest \"$(git -C four.two config remote.upstream.fetch)\" = \"+refs/heads/*:refs/remotes/upstream/*\"\n '\n \n test_expect_success 'rename a remote with name prefix of other remote' '\n \tgit clone one four.three &&\n-\t(\n-\t\tcd four.three &&\n-\t\tgit remote add o git://example.com/repo.git &&\n-\t\tgit remote rename o upstream &&\n-\t\ttest \"$(git rev-parse origin/main)\" = \"$(git rev-parse main)\"\n-\t)\n+\tgit -C four.three remote add o git://example.com/repo.git &&\n+\tgit -C four.three remote rename o upstream &&\n+\ttest \"$(git -C four.three rev-parse origin/main)\" = \"$(git -C four.three rev-parse main)\"\n '\n \n test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n@@ -923,49 +742,37 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n test_expect_success 'remove a remote' '\n \ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.five &&\n-\t(\n-\t\tcd four.five &&\n-\t\tgit config branch.main.pushRemote origin &&\n-\t\tgit remote remove origin &&\n-\t\ttest -z \"$(git for-each-ref refs/remotes/origin)\" &&\n-\t\ttest_must_fail git config branch.main.remote &&\n-\t\ttest_must_fail git config branch.main.pushRemote &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\"\n-\t)\n+\tgit -C four.five config branch.main.pushRemote origin &&\n+\tgit -C four.five remote remove origin &&\n+\ttest -z \"$(git -C four.five for-each-ref refs/remotes/origin)\" &&\n+\ttest_must_fail git -C four.five config branch.main.remote &&\n+\ttest_must_fail git -C four.five config branch.main.pushRemote &&\n+\ttest \"$(git -C four.five config --global remote.pushDefault)\" = \"origin\"\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault' '\n \tgit clone one four.five.1 &&\n-\t(\n-\t\tcd four.five.1 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote remove origin &&\n-\t\ttest_must_fail git config --local remote.pushDefault\n-\t)\n+\tgit -C four.five.1 config remote.pushDefault origin &&\n+\tgit -C four.five.1 remote remove origin &&\n+\ttest_must_fail git -C four.five.1 config --local remote.pushDefault\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n \ttest_config_global remote.pushDefault other &&\n \tgit clone one four.five.2 &&\n-\t(\n-\t\tcd four.five.2 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote remove origin &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"other\" &&\n-\t\ttest_must_fail git config --local remote.pushDefault\n-\t)\n+\tgit -C four.five.2 config remote.pushDefault origin &&\n+\tgit -C four.five.2 remote remove origin &&\n+\ttest \"$(git -C four.five.2 config --global remote.pushDefault)\" = \"other\" &&\n+\ttest_must_fail git -C four.five.2 config --local remote.pushDefault\n '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n \ttest_config_global remote.pushDefault origin &&\n \tgit clone one four.five.3 &&\n-\t(\n-\t\tcd four.five.3 &&\n-\t\tgit config remote.pushDefault origin &&\n-\t\tgit remote remove origin &&\n-\t\ttest \"$(git config --global remote.pushDefault)\" = \"origin\" &&\n-\t\ttest_must_fail git config --local remote.pushDefault\n-\t)\n+\tgit -C four.five.3 config remote.pushDefault origin &&\n+\tgit -C four.five.3 remote remove origin &&\n+\ttest \"$(git -C four.five.3 config --global remote.pushDefault)\" = \"origin\" &&\n+\ttest_must_fail git -C four.five.3 config --local remote.pushDefault\n '\n \n cat >remotes_origin <<EOF\n@@ -979,91 +786,67 @@ EOF\n test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' '\n \tgit clone one five &&\n \torigin_url=$(pwd)/one &&\n-\t(\n-\t\tcd five &&\n-\t\tgit remote remove origin &&\n-\t\tmkdir -p .git/remotes &&\n-\t\tcat ../remotes_origin >.git/remotes/origin &&\n-\t\tgit remote rename origin origin &&\n-\t\ttest_path_is_missing .git/remotes/origin &&\n-\t\ttest \"$(git config remote.origin.url)\" = \"$origin_url\" &&\n-\t\tcat >push_expected <<-\\EOF &&\n-\t\trefs/heads/main:refs/heads/upstream\n-\t\trefs/heads/next:refs/heads/upstream2\n-\t\tEOF\n-\t\tcat >fetch_expected <<-\\EOF &&\n-\t\trefs/heads/main:refs/heads/origin\n-\t\trefs/heads/next:refs/heads/origin2\n-\t\tEOF\n-\t\tgit config --get-all remote.origin.push >push_actual &&\n-\t\tgit config --get-all remote.origin.fetch >fetch_actual &&\n-\t\ttest_cmp push_expected push_actual &&\n-\t\ttest_cmp fetch_expected fetch_actual\n-\t)\n+\tgit -C five remote remove origin &&\n+\tmkdir -p five/.git/remotes &&\n+\tcat remotes_origin >five/.git/remotes/origin &&\n+\tgit -C five remote rename origin origin &&\n+\ttest_path_is_missing .git/remotes/origin &&\n+\ttest \"$(git -C five config remote.origin.url)\" = \"$origin_url\" &&\n+\tcat >push_expected <<-\\EOF &&\n+\trefs/heads/main:refs/heads/upstream\n+\trefs/heads/next:refs/heads/upstream2\n+\tEOF\n+\tcat >fetch_expected <<-\\EOF &&\n+\trefs/heads/main:refs/heads/origin\n+\trefs/heads/next:refs/heads/origin2\n+\tEOF\n+\tgit -C five config --get-all remote.origin.push >push_actual &&\n+\tgit -C five config --get-all remote.origin.fetch >fetch_actual &&\n+\ttest_cmp push_expected push_actual &&\n+\ttest_cmp fetch_expected fetch_actual\n '\n \n test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' '\n \tgit clone one six &&\n \torigin_url=$(pwd)/one &&\n-\t(\n-\t\tcd six &&\n-\t\tgit remote rm origin &&\n-\t\techo \"$origin_url#main\" >.git/branches/origin &&\n-\t\tgit remote rename origin origin &&\n-\t\ttest_path_is_missing .git/branches/origin &&\n-\t\ttest \"$(git config remote.origin.url)\" = \"$origin_url\" &&\n-\t\ttest \"$(git config remote.origin.fetch)\" = \"refs/heads/main:refs/heads/origin\" &&\n-\t\ttest \"$(git config remote.origin.push)\" = \"HEAD:refs/heads/main\"\n-\t)\n+\tgit -C six remote rm origin &&\n+\techo \"$origin_url#main\" >six/.git/branches/origin &&\n+\tgit -C six remote rename origin origin &&\n+\ttest_path_is_missing .git/branches/origin &&\n+\ttest \"$(git -C six config remote.origin.url)\" = \"$origin_url\" &&\n+\ttest \"$(git -C six config remote.origin.fetch)\" = \"refs/heads/main:refs/heads/origin\" &&\n+\ttest \"$(git -C six config remote.origin.push)\" = \"HEAD:refs/heads/main\"\n '\n \n test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' '\n \tgit clone one seven &&\n-\t(\n-\t\tcd seven &&\n-\t\tgit remote rm origin &&\n-\t\techo \"quux#foom\" > .git/branches/origin &&\n-\t\tgit remote rename origin origin &&\n-\t\ttest_path_is_missing .git/branches/origin &&\n-\t\ttest \"$(git config remote.origin.url)\" = \"quux\" &&\n-\t\ttest \"$(git config remote.origin.fetch)\" = \"refs/heads/foom:refs/heads/origin\" &&\n-\t\ttest \"$(git config remote.origin.push)\" = \"HEAD:refs/heads/foom\"\n-\t)\n+\tgit -C seven remote rm origin &&\n+\techo \"quux#foom\" >seven/.git/branches/origin &&\n+\tgit -C seven remote rename origin origin &&\n+\ttest_path_is_missing .git/branches/origin &&\n+\ttest \"$(git -C seven config remote.origin.url)\" = \"quux\" &&\n+\ttest \"$(git -C seven config remote.origin.fetch)\" = \"refs/heads/foom:refs/heads/origin\" &&\n+\ttest \"$(git -C seven config remote.origin.push)\" = \"HEAD:refs/heads/foom\"\n '\n \n test_expect_success 'remote prune to cause a dangling symref' '\n \tgit clone one eight &&\n-\t(\n-\t\tcd one &&\n-\t\tgit checkout side2 &&\n-\t\tgit branch -D main\n-\t) &&\n-\t(\n-\t\tcd eight &&\n-\t\tgit remote prune origin\n-\t) >err 2>&1 &&\n+\tgit -C one checkout side2 &&\n+\tgit -C one branch -D main &&\n+\tgit -C eight remote prune origin >err 2>&1 &&\n \ttest_i18ngrep \"has become dangling\" err &&\n \n \t: And the dangling symref will not cause other annoying errors &&\n-\t(\n-\t\tcd eight &&\n-\t\tgit branch -a\n-\t) 2>err &&\n+\tgit -C eight branch -a 2>err &&\n \t! grep \"points nowhere\" err &&\n-\t(\n-\t\tcd eight &&\n-\t\ttest_must_fail git branch nomore origin\n-\t) 2>err &&\n+\ttest_must_fail git -C eight branch nomore origin 2>err &&\n \ttest_i18ngrep \"dangling symref\" err\n '\n \n test_expect_success 'show empty remote' '\n \ttest_create_repo empty &&\n \tgit clone empty empty-clone &&\n-\t(\n-\t\tcd empty-clone &&\n-\t\tgit remote show origin\n-\t)\n+\tgit -C empty-clone remote show origin\n '\n \n test_expect_success 'remote set-branches requires a remote' '\n@@ -1100,36 +883,34 @@ test_expect_success 'remote set-branches' '\n \tEOF\n \n \tgit clone .git/ setbranches &&\n-\t(\n-\t\tcd setbranches &&\n-\t\tgit remote rename origin scratch &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.initial &&\n+\tgit -C setbranches remote rename origin scratch &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.initial &&\n \n-\t\tgit remote set-branches scratch --add other &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.add &&\n+\tgit -C setbranches remote set-branches scratch --add other &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.add &&\n \n-\t\tgit remote set-branches scratch maint main next &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.replace &&\n+\tgit -C setbranches remote set-branches scratch maint main next &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.replace &&\n \n-\t\tgit remote set-branches --add scratch seen t/topic &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.add-two &&\n+\tgit -C setbranches remote set-branches --add scratch seen t/topic &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.add-two &&\n \n-\t\tgit config --unset-all remote.scratch.fetch &&\n-\t\tgit config remote.scratch.fetch \\\n-\t\t\trefs/heads/main:refs/remotes/scratch/main &&\n-\t\tgit config --add remote.scratch.fetch \\\n-\t\t\t+refs/heads/next:refs/remotes/scratch/next &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.setup-ffonly &&\n+\tgit -C setbranches config --unset-all remote.scratch.fetch &&\n+\tgit -C setbranches config remote.scratch.fetch \\\n+\t\trefs/heads/main:refs/remotes/scratch/main &&\n+\tgit -C setbranches config --add remote.scratch.fetch \\\n+\t\t+refs/heads/next:refs/remotes/scratch/next &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.setup-ffonly &&\n+\n+\tgit -C setbranches remote set-branches --add scratch seen &&\n+\tgit -C setbranches config --get-all remote.scratch.fetch >config-result &&\n+\tsort <config-result >actual.respect-ffonly &&\n \n-\t\tgit remote set-branches --add scratch seen &&\n-\t\tgit config --get-all remote.scratch.fetch >config-result &&\n-\t\tsort <config-result >../actual.respect-ffonly\n-\t) &&\n \ttest_cmp expect.initial actual.initial &&\n \ttest_cmp expect.add actual.add &&\n \ttest_cmp expect.replace actual.replace &&\n@@ -1142,14 +923,11 @@ test_expect_success 'remote set-branches with --mirror' '\n \techo \"+refs/*:refs/*\" >expect.initial &&\n \techo \"+refs/heads/main:refs/heads/main\" >expect.replace &&\n \tgit clone --mirror .git/ setbranches-mirror &&\n-\t(\n-\t\tcd setbranches-mirror &&\n-\t\tgit remote rename origin scratch &&\n-\t\tgit config --get-all remote.scratch.fetch >../actual.initial &&\n+\tgit -C setbranches-mirror remote rename origin scratch &&\n+\tgit -C setbranches-mirror config --get-all remote.scratch.fetch >actual.initial &&\n \n-\t\tgit remote set-branches scratch heads/main &&\n-\t\tgit config --get-all remote.scratch.fetch >../actual.replace\n-\t) &&\n+\tgit -C setbranches-mirror remote set-branches scratch heads/main &&\n+\tgit -C setbranches-mirror config --get-all remote.scratch.fetch >actual.replace &&\n \ttest_cmp expect.initial actual.initial &&\n \ttest_cmp expect.replace actual.replace\n '\n@@ -1407,56 +1185,47 @@ test_expect_success 'add remote matching the \"insteadOf\" URL' '\n '\n \n test_expect_success 'unqualified <dst> refspec DWIM and advice' '\n-\ttest_when_finished \"(cd test && git tag -d some-tag)\" &&\n-\t(\n-\t\tcd test &&\n-\t\tgit tag -a -m \"Some tag\" some-tag main &&\n-\t\tfor type in commit tag tree blob\n-\t\tdo\n-\t\t\tif test \"$type\" = \"blob\"\n-\t\t\tthen\n-\t\t\t\toid=$(git rev-parse some-tag:file)\n-\t\t\telse\n-\t\t\t\toid=$(git rev-parse some-tag^{$type})\n-\t\t\tfi &&\n-\t\t\ttest_must_fail git push origin $oid:dst 2>err &&\n-\t\t\ttest_i18ngrep \"error: The destination you\" err &&\n-\t\t\ttest_i18ngrep \"hint: Did you mean\" err &&\n-\t\t\ttest_must_fail git -c advice.pushUnqualifiedRefName=false \\\n-\t\t\t\tpush origin $oid:dst 2>err &&\n-\t\t\ttest_i18ngrep \"error: The destination you\" err &&\n-\t\t\ttest_i18ngrep ! \"hint: Did you mean\" err ||\n-\t\t\texit 1\n-\t\tdone\n-\t)\n+\ttest_when_finished \"git -C test tag -d some-tag\" &&\n+\tgit -C test tag -a -m \"Some tag\" some-tag main &&\n+\tfor type in commit tag tree blob\n+\tdo\n+\t\tif test \"$type\" = \"blob\"\n+\t\tthen\n+\t\t\toid=$(git -C test rev-parse some-tag:file)\n+\t\telse\n+\t\t\toid=$(git -C test rev-parse some-tag^{$type})\n+\t\tfi &&\n+\t\ttest_must_fail git -C test push origin $oid:dst 2>err &&\n+\t\ttest_i18ngrep \"error: The destination you\" err &&\n+\t\ttest_i18ngrep \"hint: Did you mean\" err &&\n+\t\ttest_must_fail git -C test -c advice.pushUnqualifiedRefName=false \\\n+\t\t\tpush origin $oid:dst 2>err &&\n+\t\ttest_i18ngrep \"error: The destination you\" err &&\n+\t\ttest_i18ngrep ! \"hint: Did you mean\" err ||\n+\t\texit 1\n+\tdone\n '\n \n test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and advice' '\n-\t(\n-\t\tcd two &&\n-\t\tgit tag -a -m \"Some tag\" my-tag main &&\n-\t\tgit update-ref refs/trees/my-head-tree HEAD^{tree} &&\n-\t\tgit update-ref refs/blobs/my-file-blob HEAD:file\n-\t) &&\n-\t(\n-\t\tcd test &&\n-\t\tgit config --add remote.two.fetch \"+refs/tags/*:refs/remotes/tags-from-two/*\" &&\n-\t\tgit config --add remote.two.fetch \"+refs/trees/*:refs/remotes/trees-from-two/*\" &&\n-\t\tgit config --add remote.two.fetch \"+refs/blobs/*:refs/remotes/blobs-from-two/*\" &&\n-\t\tgit fetch --no-tags two &&\n+\tgit -C two tag -a -m \"Some tag\" my-tag main &&\n+\tgit -C two update-ref refs/trees/my-head-tree HEAD^{tree} &&\n+\tgit -C two update-ref refs/blobs/my-file-blob HEAD:file &&\n+\tgit -C test config --add remote.two.fetch \"+refs/tags/*:refs/remotes/tags-from-two/*\" &&\n+\tgit -C test config --add remote.two.fetch \"+refs/trees/*:refs/remotes/trees-from-two/*\" &&\n+\tgit -C test config --add remote.two.fetch \"+refs/blobs/*:refs/remotes/blobs-from-two/*\" &&\n+\tgit -C test fetch --no-tags two &&\n \n-\t\ttest_must_fail git push origin refs/remotes/two/another:dst 2>err &&\n-\t\ttest_i18ngrep \"error: The destination you\" err &&\n+\ttest_must_fail git -C test push origin refs/remotes/two/another:dst 2>err &&\n+\ttest_i18ngrep \"error: The destination you\" err &&\n \n-\t\ttest_must_fail git push origin refs/remotes/tags-from-two/my-tag:dst-tag 2>err &&\n-\t\ttest_i18ngrep \"error: The destination you\" err &&\n+\ttest_must_fail git -C test push origin refs/remotes/tags-from-two/my-tag:dst-tag 2>err &&\n+\ttest_i18ngrep \"error: The destination you\" err &&\n \n-\t\ttest_must_fail git push origin refs/remotes/trees-from-two/my-head-tree:dst-tree 2>err &&\n-\t\ttest_i18ngrep \"error: The destination you\" err &&\n+\ttest_must_fail git -C test push origin refs/remotes/trees-from-two/my-head-tree:dst-tree 2>err &&\n+\ttest_i18ngrep \"error: The destination you\" err &&\n \n-\t\ttest_must_fail git push origin refs/remotes/blobs-from-two/my-file-blob:dst-blob 2>err &&\n-\t\ttest_i18ngrep \"error: The destination you\" err\n-\t)\n+\ttest_must_fail git -C test push origin refs/remotes/blobs-from-two/my-file-blob:dst-blob 2>err &&\n+\ttest_i18ngrep \"error: The destination you\" err\n '\n \n test_done\n-- \n2.36.1\n\n"},{"id":"457443","messageId":"20220617002036.1577-5-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 4/6] tests: only automatically unset matching values from test_config","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:34Z","receivedAt":"2022-06-17T00:20:53Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.e.keller@intel.com>\n\nThe test_config function is used to set a configuration value and then\nensure that its unset at the end of the test using test_unconfig. This\ncurrently unsets all configurations with the specified name regardless\nof whether they match a value.\n\nThe git config command can optionally only unset keys which have\nspecific values. Add support for this by using the 2 argument form, and\nadd handling for the --fixed-value option.\n\nPass --fixed-value and both the key and value to the test_unconfig call\nfrom test_config. This ensures that test_config will only setup a\ntrigger to remove the matching values instead of removing all\nconfigurations of the specified key.\n\nDirectly using test_unconfig will still unset all values by default,\nunless a 2nd value-pattern parameter is provided. This matches the\nbehavior of git config and allows some control over the behavior.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n t/test-lib-functions.sh | 36 +++++++++++++++++++++++++++++++++---\n 1 file changed, 33 insertions(+), 3 deletions(-)\n\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex e518b89bf128..9957eb2e6c30 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -506,15 +506,18 @@ test_modebits () {\n \t\t\t  -e 's|^\\(......\\)S|\\1-|' -e 's|^\\(......\\)s|\\1x|'\n }\n \n-# Usage: test_unconfig [options] <name>\n+# Usage: test_unconfig [options] <name> <value-pattern>\n #   -C <dir>:\n #\tRun all git commits in directory <dir>\n #   --global:\n #\tModify the global configuration instead of repository.\n+#   --fixed-value:\n+#\tMatch the value pattern as a fixed string instead of a regex.\n #\n # Unset a configuration variable, but don't fail if it doesn't exist.\n test_unconfig () {\n \tglobal=\n+\tfixed=\n \tconfig_dir=\n \twhile test $# != 0\n \tdo\n@@ -526,6 +529,9 @@ test_unconfig () {\n \t\t--global)\n \t\t\tglobal=--global\n \t\t\t;;\n+\t\t--fixed-value)\n+\t\t\tfixed=--fixed-value\n+\t\t\t;;\n \t\t-*)\n \t\t\tBUG \"invalid test_unconfig option: $1\"\n \t\t\t;;\n@@ -535,7 +541,20 @@ test_unconfig () {\n \t\tesac\n \t\tshift\n \tdone\n-\tgit ${config_dir:+-C \"$config_dir\"} config $global --unset-all \"$1\"\n+\n+\tcase \"$#\" in\n+\t1)\n+\t\t# Only enable --fixed-value if we have two parameters\n+\t\tfixed=\n+\t\t;;\n+\t2)\n+\t\t;;\n+\t*)\n+\t\tBUG \"test_unconfig requires 1 or 2 positional arguments\"\n+\t\t;;\n+\tesac\n+\n+\tgit ${config_dir:+-C \"$config_dir\"} config $global $fixed --unset-all \"$1\" \"$2\"\n \tconfig_status=$?\n \tcase \"$config_status\" in\n \t5) # ok, nothing to unset\n@@ -575,7 +594,18 @@ test_config () {\n \t\tesac\n \t\tshift\n \tdone\n-\ttest_when_finished \"test_unconfig ${config_dir:+-C '$config_dir'} $global '$1'\" &&\n+\n+\tcase \"$#\" in\n+\t1)\n+\t\t;;\n+\t2)\n+\t\t;;\n+\t*)\n+\t\tBUG \"test_config requires 1 or 2 positional arguments\"\n+\t\t;;\n+\tesac\n+\n+\ttest_when_finished \"test_unconfig ${config_dir:+-C '$config_dir'} --fixed-value $global '$1' '$2'\" &&\n \tgit ${config_dir:+-C \"$config_dir\"} config $global \"$1\" \"$2\"\n }\n \n-- \n2.36.1\n\n"},{"id":"457444","messageId":"20220617002036.1577-7-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 6/6] remote: add test for negative refspec with prune","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:36Z","receivedAt":"2022-06-17T00:20:54Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"git remote prune does not handle negative refspecs properly. If a\nnegative refspec got added after a fetch, a user may expect that the\nresulting refs that were previously fetched would now be considered\nstale, and thus removed by git remote prune. Show that this isn't the\ncase with a new test case.\n\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\n t/t5505-remote.sh | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 8cad753023ef..0810e7d8d0b7 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -399,6 +399,19 @@ test_expect_success 'prune --dry-run' '\n \ttest_cmp expect output\n '\n \n+cat >expect <<EOF\n+Pruning origin\n+URL: $(pwd)/one\n+ * [would prune] origin/side2\n+EOF\n+\n+test_expect_failure 'prune --dry-run negative refspec' '\n+\ttest_config -C test --add remote.origin.fetch ^refs/heads/side2 &&\n+\tgit -C test remote prune --dry-run origin >output &&\n+\tgit -C test rev-parse refs/remotes/origin/side2 &&\n+\ttest_cmp expect output\n+'\n+\n test_expect_success 'add --mirror && prune' '\n \tmkdir mirror &&\n \tgit -C mirror init --bare &&\n-- \n2.36.1\n\n"},{"id":"457445","messageId":"20220617002036.1577-6-jacob.keller@gmail.com","threadId":"58026","inReplyTo":"20220617002036.1577-1-jacob.keller@gmail.com","subject":"[PATCH v3 5/6] t5505: use test_config where appropriate","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2022-06-17T00:20:35Z","receivedAt":"2022-06-17T00:20:56Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.e.keller@intel.com>\n\nThe t5505-remote.sh function makes heavy use of git config, often\nleaving potentially stale configuration which may affect future tests.\nFix this by using test_config instead, which ensures the configuration\nvalues get unset.\n\nThe t5505-remote.sh script makes use of the --add option of git config.\nTeach this option to test_config, and then use test_config where\nappropriate.\n\nSome configuration values in the 'show' test are left alone. This is\ndone because these values are actually relied upon by future tests, and\nclearing them breaks the expectations.\n\nSigned-off-by: Jacob Keller <jacob.e.keller@intel.com>\n---\n t/t5505-remote.sh       | 52 ++++++++++++++++++++---------------------\n t/test-lib-functions.sh |  6 ++++-\n 2 files changed, 30 insertions(+), 28 deletions(-)\n\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 7914379ed253..8cad753023ef 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -95,7 +95,7 @@ test_expect_success 'filters for promisor remotes are listed by git remote -v' '\n \tgit -C pc remote -v >out &&\n \tgrep \"srv.bare (fetch) \\[blob:none\\]\" out &&\n \n-\tgit -C pc config remote.origin.partialCloneFilter object:type=commit &&\n+\ttest_config -C pc remote.origin.partialCloneFilter object:type=commit &&\n \tgit -C pc remote -v >out &&\n \tgrep \"srv.bare (fetch) \\[object:type=commit\\]\" out\n '\n@@ -155,10 +155,10 @@ test_expect_success 'remove remote protects local branches' '\n \t  git branch -d main\n \tEOF\n \tgit -C test tag footag &&\n-\tgit -C test config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n+\ttest_config -C test --add remote.oops.fetch \"+refs/*:refs/*\" &&\n \tgit -C test remote remove oops 2>actual1 &&\n \tgit -C test branch foobranch &&\n-\tgit -C test config --add remote.oops.fetch \"+refs/*:refs/*\" &&\n+\ttest_config -C test --add remote.oops.fetch \"+refs/*:refs/*\" &&\n \tgit -C test remote rm oops 2>actual2 &&\n \tgit -C test branch -d foobranch &&\n \tgit -C test tag -d footag &&\n@@ -183,7 +183,7 @@ test_expect_success 'remove remote with a branch without configured merge' '\n \tgit -C test remote add two ../two &&\n \tgit -C test fetch two &&\n \tgit -C test checkout -b second two/main^0 &&\n-\tgit -C test config branch.second.remote two &&\n+\ttest_config -C test branch.second.remote two &&\n \tgit -C test checkout main &&\n \tgit -C test remote rm two\n '\n@@ -294,8 +294,7 @@ cat >expect <<EOF\n EOF\n \n test_expect_success 'show with negative refspecs' '\n-\ttest_when_finished \"git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/main\" &&\n-\tgit -C test config --add remote.origin.fetch ^refs/heads/main &&\n+\ttest_config -C test --add remote.origin.fetch ^refs/heads/main &&\n \tgit -C test remote show origin >output &&\n \ttest_cmp expect output\n '\n@@ -317,8 +316,7 @@ cat >expect <<EOF\n EOF\n \n test_expect_failure 'show stale with negative refspecs' '\n-\ttest_when_finished \"git -C test config --unset-all --fixed-value remote.origin.fetch ^refs/heads/side\" &&\n-\tgit -C test config --add remote.origin.fetch ^refs/heads/side &&\n+\ttest_config -C test --add remote.origin.fetch ^refs/heads/side &&\n \tgit -C test remote show origin >output &&\n \ttest_cmp expect output\n '\n@@ -488,8 +486,8 @@ test_expect_success 'add alt && prune' '\n \tmkdir alttst &&\n \tgit -C alttst init &&\n \tgit -C alttst remote add -f origin ../one &&\n-\tgit -C alttst config remote.alt.url ../one &&\n-\tgit -C alttst config remote.alt.fetch \"+refs/heads/*:refs/remotes/origin/*\" &&\n+\ttest_config -C alttst remote.alt.url ../one &&\n+\ttest_config -C alttst remote.alt.fetch \"+refs/heads/*:refs/remotes/origin/*\" &&\n \tgit -C one branch -m side side2 &&\n \tgit -C alttst rev-parse --verify refs/remotes/origin/side &&\n \ttest_must_fail git -C alttst rev-parse --verify refs/remotes/origin/side2 &&\n@@ -590,8 +588,8 @@ test_expect_success 'update with arguments' '\n \tdone &&\n \tgit -C one remote add manduca ../mirror &&\n \tgit -C one remote add megaloprepus ../mirror &&\n-\tgit -C one config remotes.phobaeticus \"drosophila megaloprepus\" &&\n-\tgit -C one config remotes.titanus manduca &&\n+\ttest_config -C one remotes.phobaeticus \"drosophila megaloprepus\" &&\n+\ttest_config -C one remotes.titanus manduca &&\n \tgit -C one remote update phobaeticus titanus &&\n \tgit -C one branch -r >output &&\n \ttest_cmp expect output\n@@ -619,7 +617,7 @@ test_expect_success 'update default' '\n \tdo\n \tgit -C one branch -r -d $b || exit 1\n \tdone &&\n-\tgit -C one config remote.drosophila.skipDefaultUpdate true &&\n+\ttest_config -C one remote.drosophila.skipDefaultUpdate true &&\n \tgit -C one remote update default &&\n \tgit -C one branch -r >output &&\n \ttest_cmp expect output\n@@ -636,7 +634,7 @@ test_expect_success 'update default (overridden, with funny whitespace)' '\n \tdo\n \tgit -C one branch -r -d $b || exit 1\n \tdone &&\n-\tgit -C one config remotes.default \"$(printf \"\\t drosophila  \\n\")\" &&\n+\ttest_config -C one remotes.default \"$(printf \"\\t drosophila  \\n\")\" &&\n \tgit -C one remote update default &&\n \tgit -C one branch -r >output &&\n \ttest_cmp expect output\n@@ -647,7 +645,7 @@ test_expect_success 'update (with remotes.default defined)' '\n \tdo\n \tgit -C one branch -r -d $b || exit 1\n \tdone &&\n-\tgit -C one config remotes.default \"drosophila\" &&\n+\ttest_config -C one remotes.default \"drosophila\" &&\n \tgit -C one remote update &&\n \tgit -C one branch -r >output &&\n \ttest_cmp expect output\n@@ -670,7 +668,7 @@ test_expect_success 'reject adding remote with an invalid name' '\n test_expect_success 'rename a remote' '\n \ttest_config --global remote.pushDefault origin &&\n \tgit clone one four &&\n-\tgit -C four config branch.main.pushRemote origin &&\n+\ttest_config -C four branch.main.pushRemote origin &&\n \tGIT_TRACE2_EVENT=$(pwd)/trace \\\n \t\tgit -C four remote rename --progress origin upstream &&\n \ttest_region progress \"Renaming remote references\" trace &&\n@@ -686,7 +684,7 @@ test_expect_success 'rename a remote' '\n \n test_expect_success 'rename a remote renames repo remote.pushDefault' '\n \tgit clone one four.1 &&\n-\tgit -C four.1 config remote.pushDefault origin &&\n+\ttest_config -C four.1 remote.pushDefault origin &&\n \tgit -C four.1 remote rename origin upstream &&\n \tgrep pushDefault four.1/.git/config &&\n \ttest \"$(git -C four.1 config --local remote.pushDefault)\" = \"upstream\"\n@@ -695,7 +693,7 @@ test_expect_success 'rename a remote renames repo remote.pushDefault' '\n test_expect_success 'rename a remote renames repo remote.pushDefault but ignores global' '\n \ttest_config --global remote.pushDefault other &&\n \tgit clone one four.2 &&\n-\tgit -C four.2 config remote.pushDefault origin &&\n+\ttest_config -C four.2 remote.pushDefault origin &&\n \tgit -C four.2 remote rename origin upstream &&\n \ttest \"$(git -C four.2 config --global remote.pushDefault)\" = \"other\" &&\n \ttest \"$(git -C four.2 config --local remote.pushDefault)\" = \"upstream\"\n@@ -704,7 +702,7 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but ignores\n test_expect_success 'rename a remote renames repo remote.pushDefault but keeps global' '\n \ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.3 &&\n-\tgit -C four.3 config remote.pushDefault origin &&\n+\ttest_config -C four.3 remote.pushDefault origin &&\n \tgit -C four.3 remote rename origin upstream &&\n \ttest \"$(git -C four.3 config --global remote.pushDefault)\" = \"origin\" &&\n \ttest \"$(git -C four.3 config --local remote.pushDefault)\" = \"upstream\"\n@@ -712,7 +710,7 @@ test_expect_success 'rename a remote renames repo remote.pushDefault but keeps g\n \n test_expect_success 'rename does not update a non-default fetch refspec' '\n \tgit clone one four.one &&\n-\tgit -C four.one config remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&\n+\ttest_config -C four.one remote.origin.fetch +refs/heads/*:refs/heads/origin/* &&\n \tgit -C four.one remote rename origin upstream &&\n \ttest \"$(git -C four.one config remote.upstream.fetch)\" = \"+refs/heads/*:refs/heads/origin/*\" &&\n \tgit -C four.one rev-parse -q origin/main\n@@ -742,7 +740,7 @@ test_expect_success 'rename succeeds with existing remote.<target>.prune' '\n test_expect_success 'remove a remote' '\n \ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.five &&\n-\tgit -C four.five config branch.main.pushRemote origin &&\n+\ttest_config -C four.five branch.main.pushRemote origin &&\n \tgit -C four.five remote remove origin &&\n \ttest -z \"$(git -C four.five for-each-ref refs/remotes/origin)\" &&\n \ttest_must_fail git -C four.five config branch.main.remote &&\n@@ -752,7 +750,7 @@ test_expect_success 'remove a remote' '\n \n test_expect_success 'remove a remote removes repo remote.pushDefault' '\n \tgit clone one four.five.1 &&\n-\tgit -C four.five.1 config remote.pushDefault origin &&\n+\ttest_config -C four.five.1 remote.pushDefault origin &&\n \tgit -C four.five.1 remote remove origin &&\n \ttest_must_fail git -C four.five.1 config --local remote.pushDefault\n '\n@@ -760,7 +758,7 @@ test_expect_success 'remove a remote removes repo remote.pushDefault' '\n test_expect_success 'remove a remote removes repo remote.pushDefault but ignores global' '\n \ttest_config --global remote.pushDefault other &&\n \tgit clone one four.five.2 &&\n-\tgit -C four.five.2 config remote.pushDefault origin &&\n+\ttest_config -C four.five.2 remote.pushDefault origin &&\n \tgit -C four.five.2 remote remove origin &&\n \ttest \"$(git -C four.five.2 config --global remote.pushDefault)\" = \"other\" &&\n \ttest_must_fail git -C four.five.2 config --local remote.pushDefault\n@@ -769,7 +767,7 @@ test_expect_success 'remove a remote removes repo remote.pushDefault but ignores\n test_expect_success 'remove a remote removes repo remote.pushDefault but keeps global' '\n \ttest_config --global remote.pushDefault origin &&\n \tgit clone one four.five.3 &&\n-\tgit -C four.five.3 config remote.pushDefault origin &&\n+\ttest_config -C four.five.3 remote.pushDefault origin &&\n \tgit -C four.five.3 remote remove origin &&\n \ttest \"$(git -C four.five.3 config --global remote.pushDefault)\" = \"origin\" &&\n \ttest_must_fail git -C four.five.3 config --local remote.pushDefault\n@@ -1210,9 +1208,9 @@ test_expect_success 'refs/remotes/* <src> refspec and unqualified <dst> DWIM and\n \tgit -C two tag -a -m \"Some tag\" my-tag main &&\n \tgit -C two update-ref refs/trees/my-head-tree HEAD^{tree} &&\n \tgit -C two update-ref refs/blobs/my-file-blob HEAD:file &&\n-\tgit -C test config --add remote.two.fetch \"+refs/tags/*:refs/remotes/tags-from-two/*\" &&\n-\tgit -C test config --add remote.two.fetch \"+refs/trees/*:refs/remotes/trees-from-two/*\" &&\n-\tgit -C test config --add remote.two.fetch \"+refs/blobs/*:refs/remotes/blobs-from-two/*\" &&\n+\ttest_config -C test --add remote.two.fetch \"+refs/tags/*:refs/remotes/tags-from-two/*\" &&\n+\ttest_config -C test --add remote.two.fetch \"+refs/trees/*:refs/remotes/trees-from-two/*\" &&\n+\ttest_config -C test --add remote.two.fetch \"+refs/blobs/*:refs/remotes/blobs-from-two/*\" &&\n \tgit -C test fetch --no-tags two &&\n \n \ttest_must_fail git -C test push origin refs/remotes/two/another:dst 2>err &&\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 9957eb2e6c30..7955ef03b8c4 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -574,6 +574,7 @@ test_unconfig () {\n # Set git config, automatically unsetting it after the test is over.\n test_config () {\n \tglobal=\n+\tadd=\n \tconfig_dir=\n \twhile test $# != 0\n \tdo\n@@ -585,6 +586,9 @@ test_config () {\n \t\t--global)\n \t\t\tglobal=--global\n \t\t\t;;\n+\t\t--add)\n+\t\t\tadd=--add\n+\t\t\t;;\n \t\t-*)\n \t\t\tBUG \"invalid test_config option: $1\"\n \t\t\t;;\n@@ -606,7 +610,7 @@ test_config () {\n \tesac\n \n \ttest_when_finished \"test_unconfig ${config_dir:+-C '$config_dir'} --fixed-value $global '$1' '$2'\" &&\n-\tgit ${config_dir:+-C \"$config_dir\"} config $global \"$1\" \"$2\"\n+\tgit ${config_dir:+-C \"$config_dir\"} config $global $add \"$1\" \"$2\"\n }\n \n write_script () {\n-- \n2.36.1\n\n"}]}