{"thread":{"id":"57589","subject":"[PATCH] t3200: fix antipatterns in existing branch tests","startedAt":"2022-03-21T06:52:05Z","lastAt":"2022-05-12T05:12:47Z","messageCount":7,"participants":["Tao Klerks via GitGitGadget","Ævar Arnfjörð Bjarmason","Tao Klerks","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"451699","messageId":"pull.1182.git.1647845516517.gitgitgadget@gmail.com","threadId":"57589","inReplyTo":null,"subject":"[PATCH] t3200: fix antipatterns in existing branch tests","fromName":"Tao Klerks via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-03-21T06:51:56Z","receivedAt":"2022-03-21T06:52:05Z","isPatch":true,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"From: Tao Klerks <tao@klerks.biz>\n\nFix issues in t3200 branch tests that, if copied, might catch new\ncontributors out:\n\nUse test_config to show that config state is not being intentionally\nleft to spill over into other tests.\n\nUse test_cmp_config instead of git config in subshells, so that\ngit's error code is not lost if/when an unexpected error occurs.\n\nUse output redirection and later content checking instead of\nsubshells, so that git's error code is not lost if/when an\nunexpected error occurs.\n\nTry to eliminate local-fetch-avoiding optimization as it is\nerror-prone (it is easy to check the wrong thing), hides segfaults,\nand yields only a marginal performance improvement anyway.\n\nIntroduce local helper test_set_remote to simplify the common local\npattern of setting up a remote via config.\n\nSigned-off-by: Tao Klerks <tao@klerks.biz>\n---\n    RFC: t3200: fix antipatterns in existing branch tests\n    \n    This is a cleanup of the branch tests following a case where I was\n    adding some, and did substantially the wrong thing by following existing\n    examples.\n    \n    I'm submitting this as RFC because I have a couple of significant\n    doubts:\n    \n     1. Does it make sense to do this? I believe it's a good idea to keep\n        things \"clean\" so that newcomers more easily do the right thing than\n        the wrong thing, but on the other hand, I've definitely read that we\n        have a \"don't change things unnecessarily\" bias somewhere.\n     2. What's the right pattern for the \"(git show-ref -q\n        refs/remotes/local/main || git fetch local)\" fetch-avoidance\n        optimization? Removing it adds a second to test runtimes, but Ævar\n        warned it hides segfaults\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1182%2FTaoK%2Fcleanup-t3200-tests-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1182/TaoK/cleanup-t3200-tests-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/1182\n\n t/t3200-branch.sh | 448 ++++++++++++++++++++++------------------------\n 1 file changed, 212 insertions(+), 236 deletions(-)\n\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 1bc3795847d..a4cbedd7f04 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -11,6 +11,20 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-rebase.sh\n \n+test_set_remote () {\n+\ttest_config \"remote.$1.url\" \"$2\" &&\n+\ttest_config \"remote.$1.fetch\" \"${3:-\"refs/heads/*:refs/remotes/$1/*\"}\"\n+}\n+\n+fetch_if_remote_ref_missing () {\n+\t# this is an anti-pattern: swallows segfault\n+\t#git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n+\t# this is slightly slower, up to 1s out of 6s on this set of tests:\n+\tgit fetch \"$2\"\n+\t# this doesn't work\n+\t#test_might_fail git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n+}\n+\n test_expect_success 'prepare a trivial repository' '\n \techo Hello >A &&\n \tgit update-index --add A &&\n@@ -372,11 +386,9 @@ EOF\n '\n \n test_expect_success 'git branch with column.*' '\n-\tgit config column.ui column &&\n-\tgit config column.branch \"dense\" &&\n+\ttest_config column.ui column &&\n+\ttest_config column.branch \"dense\" &&\n \tCOLUMNS=80 git branch >actual &&\n-\tgit config --unset column.branch &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c   bam   foo   l   * main   n     o/p   r\n   abc     bar   j/k   m/m   mb     o/o   q     topic\n@@ -389,9 +401,8 @@ test_expect_success 'git branch --column -v should fail' '\n '\n \n test_expect_success 'git branch -v with column.ui ignored' '\n-\tgit config column.ui column &&\n+\ttest_config column.ui column &&\n \tCOLUMNS=80 git branch -v | cut -c -8 | sed \"s/ *$//\" >actual &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c\n   abc\n@@ -435,7 +446,7 @@ test_expect_success 'git branch -m s/s s should work when s/t is deleted' '\n '\n \n test_expect_success 'config information was renamed, too' '\n-\ttest $(git config branch.s.dummy) = Hello &&\n+\ttest_cmp_config Hello branch.s.dummy &&\n \ttest_must_fail git config branch.s/s.dummy\n '\n \n@@ -493,63 +504,57 @@ test_expect_success 'git branch --copy dumps usage' '\n test_expect_success 'git branch -c d e should work' '\n \tgit branch --create-reflog d &&\n \tgit reflog exists refs/heads/d &&\n-\tgit config branch.d.dummy Hello &&\n+\ttest_config branch.d.dummy Hello &&\n \tgit branch -c d e &&\n \tgit reflog exists refs/heads/d &&\n \tgit reflog exists refs/heads/e &&\n-\techo Hello >expect &&\n-\tgit config branch.e.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.d.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.e.dummy &&\n+\ttest_cmp_config Hello branch.d.dummy\n '\n \n test_expect_success 'git branch --copy is a synonym for -c' '\n \tgit branch --create-reflog copy &&\n \tgit reflog exists refs/heads/copy &&\n-\tgit config branch.copy.dummy Hello &&\n+\ttest_config branch.copy.dummy Hello &&\n \tgit branch --copy copy copy-to &&\n \tgit reflog exists refs/heads/copy &&\n \tgit reflog exists refs/heads/copy-to &&\n-\techo Hello >expect &&\n-\tgit config branch.copy.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.copy-to.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.copy.dummy &&\n+\ttest_cmp_config Hello branch.copy-to.dummy\n '\n \n test_expect_success 'git branch -c ee ef should copy ee to create branch ef' '\n \tgit checkout -b ee &&\n \tgit reflog exists refs/heads/ee &&\n-\tgit config branch.ee.dummy Hello &&\n+\ttest_config branch.ee.dummy Hello &&\n \tgit branch -c ee ef &&\n \tgit reflog exists refs/heads/ee &&\n \tgit reflog exists refs/heads/ef &&\n-\ttest $(git config branch.ee.dummy) = Hello &&\n-\ttest $(git config branch.ef.dummy) = Hello &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = ee\n+\ttest_cmp_config Hello branch.ee.dummy &&\n+\ttest_cmp_config Hello branch.ef.dummy &&\n+\techo ee >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'git branch -c f/f g/g should work' '\n \tgit branch --create-reflog f/f &&\n \tgit reflog exists refs/heads/f/f &&\n-\tgit config branch.f/f.dummy Hello &&\n+\ttest_config branch.f/f.dummy Hello &&\n \tgit branch -c f/f g/g &&\n \tgit reflog exists refs/heads/f/f &&\n \tgit reflog exists refs/heads/g/g &&\n-\ttest $(git config branch.f/f.dummy) = Hello &&\n-\ttest $(git config branch.g/g.dummy) = Hello\n+\ttest_cmp_config Hello branch.f/f.dummy &&\n+\ttest_cmp_config Hello branch.g/g.dummy\n '\n \n test_expect_success 'git branch -c m2 m2 should work' '\n \tgit branch --create-reflog m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\tgit config branch.m2.dummy Hello &&\n+\ttest_config branch.m2.dummy Hello &&\n \tgit branch -c m2 m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\ttest $(git config branch.m2.dummy) = Hello\n+\ttest_cmp_config Hello branch.m2.dummy\n '\n \n test_expect_success 'git branch -c zz zz/zz should fail' '\n@@ -619,15 +624,15 @@ test_expect_success 'git branch -C main5 main5 should work when main is checked\n test_expect_success 'git branch -C ab cd should overwrite existing config for cd' '\n \tgit branch --create-reflog cd &&\n \tgit reflog exists refs/heads/cd &&\n-\tgit config branch.cd.dummy CD &&\n+\ttest_config branch.cd.dummy CD &&\n \tgit branch --create-reflog ab &&\n \tgit reflog exists refs/heads/ab &&\n-\tgit config branch.ab.dummy AB &&\n+\ttest_config branch.ab.dummy AB &&\n \tgit branch -C ab cd &&\n \tgit reflog exists refs/heads/ab &&\n \tgit reflog exists refs/heads/cd &&\n-\ttest $(git config branch.ab.dummy) = AB &&\n-\ttest $(git config branch.cd.dummy) = AB\n+\ttest_cmp_config AB branch.ab.dummy &&\n+\ttest_cmp_config AB branch.cd.dummy\n '\n \n test_expect_success 'git branch -c correctly copies multiple config sections' '\n@@ -761,75 +766,67 @@ test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '\n '\n \n test_expect_success 'test tracking setup via --track' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track my1 local/main &&\n-\ttest $(git config branch.my1.remote) = local &&\n-\ttest $(git config branch.my1.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my1.remote &&\n+\ttest_cmp_config refs/heads/main branch.my1.merge\n '\n \n test_expect_success 'test tracking setup (non-wildcard, matching)' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/main:refs/remotes/local/main &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . refs/heads/main:refs/remotes/local/main &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track my4 local/main &&\n-\ttest $(git config branch.my4.remote) = local &&\n-\ttest $(git config branch.my4.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my4.remote &&\n+\ttest_cmp_config refs/heads/main branch.my4.merge\n '\n \n test_expect_success 'tracking setup fails on non-matching refspec' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n-\tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n+\ttest_config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n \ttest_must_fail git branch --track my5 local/main &&\n \ttest_must_fail git config branch.my5.remote &&\n \ttest_must_fail git config branch.my5.merge\n '\n \n test_expect_success 'test tracking setup via config' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch my3 local/main &&\n-\ttest $(git config branch.my3.remote) = local &&\n-\ttest $(git config branch.my3.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my3.remote &&\n+\ttest_cmp_config refs/heads/main branch.my3.merge\n '\n \n test_expect_success 'test overriding tracking setup via --no-track' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track my2 local/main &&\n-\tgit config branch.autosetupmerge false &&\n-\t! test \"$(git config branch.my2.remote)\" = local &&\n-\t! test \"$(git config branch.my2.merge)\" = refs/heads/main\n+\t! test_cmp_config local branch.my2.remote &&\n+\t! test_cmp_config refs/heads/main branch.my2.merge\n '\n \n test_expect_success 'no tracking without .fetch entries' '\n-\tgit config branch.autosetupmerge true &&\n+\ttest_config branch.autosetupmerge true &&\n \tgit branch my6 s &&\n-\tgit config branch.autosetupmerge false &&\n-\ttest -z \"$(git config branch.my6.remote)\" &&\n-\ttest -z \"$(git config branch.my6.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my6.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my6.merge\n '\n \n test_expect_success 'test tracking setup via --track but deeper' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing o/o local &&\n \tgit branch --track my7 local/o/o &&\n-\ttest \"$(git config branch.my7.remote)\" = local &&\n-\ttest \"$(git config branch.my7.merge)\" = refs/heads/o/o\n+\ttest_cmp_config local branch.my7.remote &&\n+\ttest_cmp_config refs/heads/o/o branch.my7.merge\n '\n \n test_expect_success 'test deleting branch deletes branch config' '\n \tgit branch -d my7 &&\n-\ttest -z \"$(git config branch.my7.remote)\" &&\n-\ttest -z \"$(git config branch.my7.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my7.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my7.merge\n '\n \n test_expect_success 'test deleting branch without config' '\n@@ -850,14 +847,15 @@ test_expect_success 'deleting currently checked out branch fails' '\n \n test_expect_success 'test --track without .fetch entries' '\n \tgit branch --track my8 &&\n-\ttest \"$(git config branch.my8.remote)\" &&\n-\ttest \"$(git config branch.my8.merge)\"\n+\tgit config branch.my8.remote >out &&\n+\ttest -s out &&\n+\tgit config branch.my8.merge >out &&\n+\ttest -s out\n '\n \n test_expect_success 'branch from non-branch HEAD w/autosetupmerge=always' '\n-\tgit config branch.autosetupmerge always &&\n-\tgit branch my9 HEAD^ &&\n-\tgit config branch.autosetupmerge false\n+\ttest_config branch.autosetupmerge always &&\n+\tgit branch my9 HEAD^\n '\n \n test_expect_success 'branch from non-branch HEAD w/--track causes failure' '\n@@ -913,16 +911,16 @@ test_expect_success 'use --set-upstream-to modify HEAD' '\n \ttest_config branch.main.merge foo &&\n \tgit branch my12 &&\n \tgit branch --set-upstream-to my12 &&\n-\ttest \"$(git config branch.main.remote)\" = \".\" &&\n-\ttest \"$(git config branch.main.merge)\" = \"refs/heads/my12\"\n+\ttest_cmp_config \".\" branch.main.remote &&\n+\ttest_cmp_config \"refs/heads/my12\" branch.main.merge\n '\n \n test_expect_success 'use --set-upstream-to modify a particular branch' '\n \tgit branch my13 &&\n \tgit branch --set-upstream-to main my13 &&\n \ttest_when_finished \"git branch --unset-upstream my13\" &&\n-\ttest \"$(git config branch.my13.remote)\" = \".\" &&\n-\ttest \"$(git config branch.my13.merge)\" = \"refs/heads/main\"\n+\ttest_cmp_config \".\" branch.my13.remote &&\n+\ttest_cmp_config \"refs/heads/main\" branch.my13.merge\n '\n \n test_expect_success '--unset-upstream should fail if given a non-existent branch' '\n@@ -1003,273 +1001,251 @@ test_expect_success 'git checkout -b g/h/i -l should create a branch and a log'\n \n test_expect_success 'checkout -b makes reflog by default' '\n \tgit checkout main &&\n-\tgit config --unset core.logAllRefUpdates &&\n+\ttest_unconfig core.logAllRefUpdates &&\n \tgit checkout -b alpha &&\n \tgit rev-parse --verify alpha@{0}\n '\n \n test_expect_success 'checkout -b does not make reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n-\tgit config core.logAllRefUpdates false &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -b beta &&\n \ttest_must_fail git rev-parse --verify beta@{0}\n '\n \n test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -lb gamma &&\n-\tgit config --unset core.logAllRefUpdates &&\n \tgit rev-parse --verify gamma@{0}\n '\n \n test_expect_success 'avoid ambiguous track' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.ambi1.url lalala &&\n-\tgit config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&\n-\tgit config remote.ambi2.url lilili &&\n-\tgit config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote ambi1 lalala refs/heads/lalala:refs/heads/main &&\n+\ttest_set_remote ambi2 lilili refs/heads/lilili:refs/heads/main &&\n \ttest_must_fail git branch all1 main &&\n-\ttest -z \"$(git config branch.all1.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.all1.merge\n '\n \n test_expect_success 'autosetuprebase local on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tfetch_if_remote_ref_missing o local &&\n \tgit branch mybase &&\n \tgit branch --track myr1 mybase &&\n-\ttest \"$(git config branch.myr1.remote)\" = . &&\n-\ttest \"$(git config branch.myr1.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr1.rebase)\" = true\n+\ttest_cmp_config . branch.myr1.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr1.merge &&\n+\ttest_cmp_config true branch.myr1.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase always &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase always &&\n+\tfetch_if_remote_ref_missing o local &&\n \tgit branch mybase2 &&\n \tgit branch --track myr2 mybase &&\n-\ttest \"$(git config branch.myr2.remote)\" = . &&\n-\ttest \"$(git config branch.myr2.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr2.rebase)\" = true\n+\ttest_cmp_config . branch.myr2.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr2.merge &&\n+\ttest_cmp_config true branch.myr2.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tfetch_if_remote_ref_missing o local &&\n \tgit branch mybase3 &&\n \tgit branch --track myr3 mybase2 &&\n-\ttest \"$(git config branch.myr3.remote)\" = . &&\n-\ttest \"$(git config branch.myr3.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr3.rebase)\" = true\n+\ttest_cmp_config . branch.myr3.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr3.merge &&\n+\t! test_cmp_config true branch.myr3.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tfetch_if_remote_ref_missing o local &&\n \tgit branch mybase4 &&\n \tgit branch --track myr4 mybase2 &&\n-\ttest \"$(git config branch.myr4.remote)\" = . &&\n-\ttest \"$(git config branch.myr4.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr4.rebase)\" = true\n+\ttest_cmp_config . branch.myr4.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr4.merge &&\n+\t! test_cmp_config true branch.myr4.rebase\n '\n \n test_expect_success 'autosetuprebase local on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track myr5 local/main &&\n-\ttest \"$(git config branch.myr5.remote)\" = local &&\n-\ttest \"$(git config branch.myr5.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr5.rebase)\" = true\n+\ttest_cmp_config local branch.myr5.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr5.merge &&\n+\t! test_cmp_config true branch.myr5.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track myr6 local/main &&\n-\ttest \"$(git config branch.myr6.remote)\" = local &&\n-\ttest \"$(git config branch.myr6.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr6.rebase)\" = true\n+\ttest_cmp_config local branch.myr6.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr6.merge &&\n+\t! test_cmp_config true branch.myr6.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track myr7 local/main &&\n-\ttest \"$(git config branch.myr7.remote)\" = local &&\n-\ttest \"$(git config branch.myr7.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr7.rebase)\" = true\n+\ttest_cmp_config local branch.myr7.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr7.merge &&\n+\ttest_cmp_config true branch.myr7.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track myr8 local/main &&\n-\ttest \"$(git config branch.myr8.remote)\" = local &&\n-\ttest \"$(git config branch.myr8.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr8.rebase)\" = true\n+\ttest_cmp_config local branch.myr8.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr8.merge &&\n+\ttest_cmp_config true branch.myr8.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' '\n-\tgit config --unset branch.autosetuprebase &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_unconfig branch.autosetuprebase &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --track myr9 local/main &&\n-\ttest \"$(git config branch.myr9.remote)\" = local &&\n-\ttest \"$(git config branch.myr9.merge)\" = refs/heads/main &&\n-\ttest \"z$(git config branch.myr9.rebase)\" = z\n+\ttest_cmp_config local branch.myr9.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr9.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr9.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing o local &&\n \tgit branch mybase10 &&\n \tgit branch --track myr10 mybase2 &&\n-\ttest \"$(git config branch.myr10.remote)\" = . &&\n-\ttest \"$(git config branch.myr10.merge)\" = refs/heads/mybase2 &&\n-\ttest \"z$(git config branch.myr10.rebase)\" = z\n+\ttest_cmp_config . branch.myr10.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr10.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr10.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr11 mybase2 &&\n-\ttest \"z$(git config branch.myr11.remote)\" = z &&\n-\ttest \"z$(git config branch.myr11.merge)\" = z &&\n-\ttest \"z$(git config branch.myr11.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr12 local/main &&\n-\ttest \"z$(git config branch.myr12.remote)\" = z &&\n-\ttest \"z$(git config branch.myr12.merge)\" = z &&\n-\ttest \"z$(git config branch.myr12.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked local branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr13 mybase2 &&\n-\ttest \"z$(git config branch.myr13.remote)\" = z &&\n-\ttest \"z$(git config branch.myr13.merge)\" = z &&\n-\ttest \"z$(git config branch.myr13.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked local branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr14 mybase2 &&\n-\ttest \"z$(git config branch.myr14.remote)\" = z &&\n-\ttest \"z$(git config branch.myr14.merge)\" = z &&\n-\ttest \"z$(git config branch.myr14.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked local branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr15 mybase2 &&\n-\ttest \"z$(git config branch.myr15.remote)\" = z &&\n-\ttest \"z$(git config branch.myr15.merge)\" = z &&\n-\ttest \"z$(git config branch.myr15.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked local branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr16 mybase2 &&\n-\ttest \"z$(git config branch.myr16.remote)\" = z &&\n-\ttest \"z$(git config branch.myr16.merge)\" = z &&\n-\ttest \"z$(git config branch.myr16.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked remote branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr17 local/main &&\n-\ttest \"z$(git config branch.myr17.remote)\" = z &&\n-\ttest \"z$(git config branch.myr17.merge)\" = z &&\n-\ttest \"z$(git config branch.myr17.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked remote branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr18 local/main &&\n-\ttest \"z$(git config branch.myr18.remote)\" = z &&\n-\ttest \"z$(git config branch.myr18.merge)\" = z &&\n-\ttest \"z$(git config branch.myr18.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked remote branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr19 local/main &&\n-\ttest \"z$(git config branch.myr19.remote)\" = z &&\n-\ttest \"z$(git config branch.myr19.merge)\" = z &&\n-\ttest \"z$(git config branch.myr19.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked remote branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tfetch_if_remote_ref_missing main local &&\n \tgit branch --no-track myr20 local/main &&\n-\ttest \"z$(git config branch.myr20.remote)\" = z &&\n-\ttest \"z$(git config branch.myr20.merge)\" = z &&\n-\ttest \"z$(git config branch.myr20.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.rebase\n '\n \n test_expect_success 'autosetuprebase always on detached HEAD' '\n-\tgit config branch.autosetupmerge always &&\n+\ttest_config branch.autosetupmerge always &&\n \ttest_when_finished git checkout main &&\n \tgit checkout HEAD^0 &&\n \tgit branch my11 &&\n-\ttest -z \"$(git config branch.my11.remote)\" &&\n-\ttest -z \"$(git config branch.my11.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my11.rebase\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (bad value)' '\n-\tgit config branch.autosetuprebase garbage &&\n+\ttest_config branch.autosetuprebase garbage &&\n \ttest_must_fail git branch\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n-\tgit config --unset branch.autosetuprebase &&\n+\ttest_unconfig branch.autosetuprebase &&\n \techo \"[branch] autosetuprebase\" >>.git/config &&\n \ttest_must_fail git branch &&\n \tgit config --unset branch.autosetuprebase\n@@ -1277,7 +1253,7 @@ test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n \n test_expect_success 'attempt to delete a branch without base and unmerged to HEAD' '\n \tgit checkout my9 &&\n-\tgit config --unset branch.my8.merge &&\n+\ttest_unconfig branch.my8.merge &&\n \ttest_must_fail git branch -d my8\n '\n \n@@ -1285,7 +1261,7 @@ test_expect_success 'attempt to delete a branch merged to its base' '\n \t# we are on my9 which is the initial commit; traditionally\n \t# we would not have allowed deleting my8 that is not merged\n \t# to my9, but it is set to track main that already has my8\n-\tgit config branch.my8.merge refs/heads/main &&\n+\ttest_config branch.my8.merge refs/heads/main &&\n \tgit branch -d my8\n '\n \n@@ -1397,8 +1373,8 @@ test_expect_success 'tracking with unexpected .fetch refspec' '\n \t\tgit config remote.c.fetch \"+refs/remotes/*:refs/remotes/*\" &&\n \t\tgit fetch c &&\n \t\tgit branch --track local/a/main remotes/a/main &&\n-\t\ttest \"$(git config branch.local/a/main.remote)\" = \"c\" &&\n-\t\ttest \"$(git config branch.local/a/main.merge)\" = \"refs/remotes/a/main\" &&\n+\t\ttest_cmp_config \"c\" branch.local/a/main.remote &&\n+\t\ttest_cmp_config \"refs/remotes/a/main\" branch.local/a/main.merge &&\n \t\tgit rev-parse --verify a >expect &&\n \t\tgit rev-parse --verify local/a/main >actual &&\n \t\ttest_cmp expect actual\n\nbase-commit: 4c53a8c20f8984adb226293a3ffd7b88c3f4ac1a\n-- \ngitgitgadget\n"},{"id":"451725","messageId":"220321.86mthj9zny.gmgdl@evledraar.gmail.com","threadId":"57589","inReplyTo":"pull.1182.git.1647845516517.gitgitgadget@gmail.com","subject":"Re: [PATCH] t3200: fix antipatterns in existing branch tests","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2022-03-21T13:47:19Z","receivedAt":"2022-03-21T13:58:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Mar 21 2022, Tao Klerks via GitGitGadget wrote:\n\n> +fetch_if_remote_ref_missing () {\n> +\t# this is an anti-pattern: swallows segfault\n> +\t#git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n> +\t# this is slightly slower, up to 1s out of 6s on this set of tests:\n> +\tgit fetch \"$2\"\n> +\t# this doesn't work\n> +\t#test_might_fail git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n> +}\n\nMoving the context around a bit, as this refers to this code above:\n\n>     I'm submitting this as RFC because I have a couple of significant\n>     doubts:\n>     \n>      1. Does it make sense to do this? I believe it's a good idea to keep\n>         things \"clean\" so that newcomers more easily do the right thing than\n>         the wrong thing, but on the other hand, I've definitely read that we\n>         have a \"don't change things unnecessarily\" bias somewhere.\n>      2. What's the right pattern for the \"(git show-ref -q\n>         refs/remotes/local/main || git fetch local)\" fetch-avoidance\n>         optimization? Removing it adds a second to test runtimes, but Ævar\n>         warned it hides segfaults\n\nSo first, 6s? Is this on Windows? I tried running this v.s. master:\n    \n    $ git hyperfine -L rev origin/master,HEAD~,HEAD -s 'make' '(cd t && ./t3200-branch.sh)'\n    Benchmark 1: (cd t && ./t3200-branch.sh)' in 'origin/master\n      Time (mean ± σ):      1.887 s ±  0.095 s    [User: 1.534 s, System: 0.514 s]\n      Range (min … max):    1.826 s …  2.117 s    10 runs\n    \n    Benchmark 2: (cd t && ./t3200-branch.sh)' in 'HEAD~\n      Time (mean ± σ):      2.132 s ±  0.013 s    [User: 1.742 s, System: 0.561 s]\n      Range (min … max):    2.120 s …  2.166 s    10 runs\n    \n    Benchmark 3: (cd t && ./t3200-branch.sh)' in 'HEAD\n      Time (mean ± σ):      1.944 s ±  0.005 s    [User: 1.620 s, System: 0.495 s]\n      Range (min … max):    1.938 s …  1.953 s    10 runs\n    \n    Summary\n      '(cd t && ./t3200-branch.sh)' in 'origin/master' ran\n        1.03 ± 0.05 times faster than '(cd t && ./t3200-branch.sh)' in 'HEAD'\n        1.13 ± 0.06 times faster than '(cd t && ./t3200-branch.sh)' in 'HEAD~'\n\nThe HEAD~ there is your patch here, and HEAD is my fix-up. I.e.:\n\t\n\tdiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\n\tindex 9bd621ed97e..7f7b3b28581 100755\n\t--- a/t/t3200-branch.sh\n\t+++ b/t/t3200-branch.sh\n\t@@ -17,12 +17,14 @@ test_set_remote () {\n\t }\n\t \n\t fetch_if_remote_ref_missing () {\n\t-\t# this is an anti-pattern: swallows segfault\n\t-\t#git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n\t-\t# this is slightly slower, up to 1s out of 6s on this set of tests:\n\t-\tgit fetch \"$2\"\n\t-\t# this doesn't work\n\t-\t#test_might_fail git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n\t+\ttest_when_finished \"rm -f ref\" &&\n\t+\ttest_might_fail git rev-parse -q --verify \"refs/remotes/$2/$1\" >ref\n\t+\tif ! test -s ref\n\t+\tthen\n\t+\t\t# Purely an optimization, makes the test run ~10%\n\t+\t\t# faster.\n\t+\t\tgit fetch \"$2\"\n\t+\tfi\n\t }\n\t \n\t test_expect_success 'prepare a trivial repository' '\n\nThat's a safe way to do it that won't hide segfaults.\n\nIn *general* it's a bit painful to convert some of these, because we\nreally should refactor out the whole bit after \"exit_code=$?\" in\ntest_must_fail in test-lib-functions.sh into a utility\nfunction. I.e. have the ability to run an arbitrary command, and then\nafter-the-fact ask if its exit code was OK.\n\nIf you'd like to refactor that that would be most welcome, and it\n*would* help to convert some of these...\n\nBut in this case we can just use \"rev-parse -q --verify\", or rather,\nnothing :)\n\nI.e. my bias would be to just not try to optimize this, i.e. just\nconvert the users to the equivalent of a:\n\n    git fetch \"$2\"\n\nI.e. it's also useful to see that we behave correctly in the noop case,\nand as there's no behavior difference it's a marginally more useful test\nas a result.\n\nAnd if you are trying to optimize this on Windows as I suspect I think\nit's better to not do it. ~5s is the time it takes it just to get out of\nbed in the morning as far as our test runtimes are concerned.\n\nThe real underlying issue is presumably its the shelling we'll do in\n\"git fetch\", which we can eventually fix, and then make it approximately\nthe cost of the rev-parse when run locally...\n"},{"id":"451922","messageId":"CAPMMpoiYY=19Bb5uVV__FMbty+Z=G3xm+Y4=ZhVE5TR2guwaOg@mail.gmail.com","threadId":"57589","inReplyTo":"220321.86mthj9zny.gmgdl@evledraar.gmail.com","subject":"Re: [PATCH] t3200: fix antipatterns in existing branch tests","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-03-22T19:22:47Z","receivedAt":"2022-03-22T19:23:06Z","isPatch":true,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"On Mon, Mar 21, 2022 at 2:57 PM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n>\n> On Mon, Mar 21 2022, Tao Klerks via GitGitGadget wrote:\n>\n> > +fetch_if_remote_ref_missing () {\n> > +     # this is an anti-pattern: swallows segfault\n> > +     #git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n> > +     # this is slightly slower, up to 1s out of 6s on this set of tests:\n> > +     git fetch \"$2\"\n> > +     # this doesn't work\n> > +     #test_might_fail git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n> > +}\n>\n> Moving the context around a bit, as this refers to this code above:\n>\n> >     I'm submitting this as RFC because I have a couple of significant\n> >     doubts:\n> >\n> >      1. Does it make sense to do this? I believe it's a good idea to keep\n> >         things \"clean\" so that newcomers more easily do the right thing than\n> >         the wrong thing, but on the other hand, I've definitely read that we\n> >         have a \"don't change things unnecessarily\" bias somewhere.\n> >      2. What's the right pattern for the \"(git show-ref -q\n> >         refs/remotes/local/main || git fetch local)\" fetch-avoidance\n> >         optimization? Removing it adds a second to test runtimes, but Ævar\n> >         warned it hides segfaults\n>\n> So first, 6s? Is this on Windows?\n\nEh, kind of. It's Ubuntu running under a WSL2 VM, which in my\nexperience so far runs *almost* as fast as bare-metal - certainly with\nnone of the per-process or per-disk-access overheads of Windows.\n\nIt looks like my hardware is a little more \"vintage\" than yours, and\nmore importantly during my initial testing I had some significant\noverhead and variability from VS Code's server trying to track file\nchanges.\n\n> I tried running this v.s. master:\n>\n>     $ git hyperfine -L rev origin/master,HEAD~,HEAD -s 'make' '(cd t && ./t3200-branch.sh)'\n>     Benchmark 1: (cd t && ./t3200-branch.sh)' in 'origin/master\n>       Time (mean ± σ):      1.887 s ±  0.095 s    [User: 1.534 s, System: 0.514 s]\n>       Range (min … max):    1.826 s …  2.117 s    10 runs\n>\n>     Benchmark 2: (cd t && ./t3200-branch.sh)' in 'HEAD~\n>       Time (mean ± σ):      2.132 s ±  0.013 s    [User: 1.742 s, System: 0.561 s]\n>       Range (min … max):    2.120 s …  2.166 s    10 runs\n>\n>     Benchmark 3: (cd t && ./t3200-branch.sh)' in 'HEAD\n>       Time (mean ± σ):      1.944 s ±  0.005 s    [User: 1.620 s, System: 0.495 s]\n>       Range (min … max):    1.938 s …  1.953 s    10 runs\n>\n>     Summary\n>       '(cd t && ./t3200-branch.sh)' in 'origin/master' ran\n>         1.03 ± 0.05 times faster than '(cd t && ./t3200-branch.sh)' in 'HEAD'\n>         1.13 ± 0.06 times faster than '(cd t && ./t3200-branch.sh)' in 'HEAD~'\n>\n\nWhen applying this more rigorous testing approach (without your\ngit-hyperfine setup, which I haven't understood yet), without VSCode\nin the way, I get slower but similar outcomes:\n\n~/git/t$ git checkout cleanup-t3200-tests 2>/dev/null && hyperfine\n'./t3200-branch.sh' && git checkout cleanup-t3200-tests~ 2>/dev/null\n&& hyperfine './t3200-branch.sh' && git checkout cleanup-t3200-tests~2\n2>/dev/null && hyperfine './t3200-branch.sh'\n\nBenchmark 1: ./t3200-branch.sh\n  Time (mean ± σ):      3.372 s ±  0.030 s    [User: 2.945 s, System: 0.825 s]\n  Range (min … max):    3.336 s …  3.417 s    10 runs\n\nBenchmark 1: ./t3200-branch.sh\n  Time (mean ± σ):      3.630 s ±  0.032 s    [User: 3.134 s, System: 0.898 s]\n  Range (min … max):    3.592 s …  3.668 s    10 runs\n\nBenchmark 1: ./t3200-branch.sh\n  Time (mean ± σ):      3.097 s ±  0.055 s    [User: 2.741 s, System: 0.730 s]\n  Range (min … max):    3.018 s …  3.216 s    10 runs\n\nUpshot: some of my other changes had improved performance by 10%, the\nunconditional git fetch had worsened performance by 20%, and your\nchange fixed the latter.\n\n>\n> That's a safe way to do it that won't hide segfaults.\n>\n\nThx!\n\n> In *general* it's a bit painful to convert some of these, because we\n> really should refactor out the whole bit after \"exit_code=$?\" in\n> test_must_fail in test-lib-functions.sh into a utility\n> function. I.e. have the ability to run an arbitrary command, and then\n> after-the-fact ask if its exit code was OK.\n>\n> If you'd like to refactor that that would be most welcome, and it\n> *would* help to convert some of these...\n\nI'm interested, but this looks like it would require bash-fu far\nbeyond my level.\n\n>\n> But in this case we can just use \"rev-parse -q --verify\", or rather,\n> nothing :)\n>\n> I.e. my bias would be to just not try to optimize this, i.e. just\n> convert the users to the equivalent of a:\n>\n>     git fetch \"$2\"\n>\n> I.e. it's also useful to see that we behave correctly in the noop case,\n> and as there's no behavior difference it's a marginally more useful test\n> as a result.\n\nI will happily buy this argument; I also like that the simple \"git\nfetch\" call is inherently clearer/more legible than any alternative.\n\n>\n> And if you are trying to optimize this on Windows as I suspect I think\n> it's better to not do it. ~5s is the time it takes it just to get out of\n> bed in the morning as far as our test runtimes are concerned.\n>\n> The real underlying issue is presumably its the shelling we'll do in\n> \"git fetch\", which we can eventually fix, and then make it approximately\n> the cost of the rev-parse when run locally...\n\nMakes sense, but not the case. I was just being oversensitive I guess.\n"},{"id":"451935","messageId":"pull.1182.v2.git.1647995031417.gitgitgadget@gmail.com","threadId":"57589","inReplyTo":"pull.1182.git.1647845516517.gitgitgadget@gmail.com","subject":"[PATCH v2] t3200: fix antipatterns in existing branch tests","fromName":"Tao Klerks via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-03-23T00:23:51Z","receivedAt":"2022-03-23T00:24:01Z","isPatch":true,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"From: Tao Klerks <tao@klerks.biz>\n\nFix issues in t3200 branch tests that, if copied, might catch new\ncontributors out:\n\nUse test_config to show that config state is not being intentionally\nleft to spill over into other tests.\n\nUse test_cmp_config instead of git config in subshells, so that\ngit's error code is not lost if/when an unexpected error occurs.\n\nUse output redirection and later content checking instead of\nsubshells, so that git's error code is not lost if/when an\nunexpected error occurs.\n\nEliminate local-fetch-avoiding optimization as it is error-prone (it\nis easy to check the wrong thing), hides segfaults, and yields only\na marginal performance improvement given the fetch is local.\n\nIntroduce local helper test_set_remote to simplify the common local\npattern of setting up a remote via config.\n\nSigned-off-by: Tao Klerks <tao@klerks.biz>\n---\n    t3200: fix antipatterns in existing branch tests\n    \n    This is a cleanup of the branch tests following a case where I was\n    adding some, and did substantially the wrong thing by following existing\n    examples.\n    \n    I believe this third version addresses all my concerns and Ævar's\n    suggestions.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1182%2FTaoK%2Fcleanup-t3200-tests-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1182/TaoK/cleanup-t3200-tests-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/1182\n\nRange-diff vs v1:\n\n 1:  983254bc2eb ! 1:  e4addb910f7 t3200: fix antipatterns in existing branch tests\n     @@ Commit message\n          subshells, so that git's error code is not lost if/when an\n          unexpected error occurs.\n      \n     -    Try to eliminate local-fetch-avoiding optimization as it is\n     -    error-prone (it is easy to check the wrong thing), hides segfaults,\n     -    and yields only a marginal performance improvement anyway.\n     +    Eliminate local-fetch-avoiding optimization as it is error-prone (it\n     +    is easy to check the wrong thing), hides segfaults, and yields only\n     +    a marginal performance improvement given the fetch is local.\n      \n          Introduce local helper test_set_remote to simplify the common local\n          pattern of setting up a remote via config.\n     @@ t/t3200-branch.sh: export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n      +\ttest_config \"remote.$1.url\" \"$2\" &&\n      +\ttest_config \"remote.$1.fetch\" \"${3:-\"refs/heads/*:refs/remotes/$1/*\"}\"\n      +}\n     -+\n     -+fetch_if_remote_ref_missing () {\n     -+\t# this is an anti-pattern: swallows segfault\n     -+\t#git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n     -+\t# this is slightly slower, up to 1s out of 6s on this set of tests:\n     -+\tgit fetch \"$2\"\n     -+\t# this doesn't work\n     -+\t#test_might_fail git show-ref -q \"refs/remotes/$2/$1\" || git fetch \"$2\"\n     -+}\n      +\n       test_expect_success 'prepare a trivial repository' '\n       \techo Hello >A &&\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track my1 local/main &&\n      -\ttest $(git config branch.my1.remote) = local &&\n      -\ttest $(git config branch.my1.merge) = refs/heads/main\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\tgit config remote.local.fetch refs/heads/main:refs/remotes/local/main &&\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . refs/heads/main:refs/remotes/local/main &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track my4 local/main &&\n      -\ttest $(git config branch.my4.remote) = local &&\n      -\ttest $(git config branch.my4.merge) = refs/heads/main\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      -\tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n      +\ttest_config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n       \ttest_must_fail git branch --track my5 local/main &&\n       \ttest_must_fail git config branch.my5.remote &&\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetupmerge true &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch my3 local/main &&\n      -\ttest $(git config branch.my3.remote) = local &&\n      -\ttest $(git config branch.my3.merge) = refs/heads/main\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetupmerge true &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track my2 local/main &&\n      -\tgit config branch.autosetupmerge false &&\n      -\t! test \"$(git config branch.my2.remote)\" = local &&\n     @@ t/t3200-branch.sh: test_expect_success SYMLINKS 'git branch -m with symlinked .g\n      -\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n      -\t(git show-ref -q refs/remotes/local/o/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing o/o local &&\n     ++\tgit fetch local &&\n       \tgit branch --track my7 local/o/o &&\n      -\ttest \"$(git config branch.my7.remote)\" = local &&\n      -\ttest \"$(git config branch.my7.merge)\" = refs/heads/o/o\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase local &&\n     -+\tfetch_if_remote_ref_missing o local &&\n     ++\tgit fetch local &&\n       \tgit branch mybase &&\n       \tgit branch --track myr1 mybase &&\n      -\ttest \"$(git config branch.myr1.remote)\" = . &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase always &&\n     -+\tfetch_if_remote_ref_missing o local &&\n     ++\tgit fetch local &&\n       \tgit branch mybase2 &&\n       \tgit branch --track myr2 mybase &&\n      -\ttest \"$(git config branch.myr2.remote)\" = . &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase remote &&\n     -+\tfetch_if_remote_ref_missing o local &&\n     ++\tgit fetch local &&\n       \tgit branch mybase3 &&\n       \tgit branch --track myr3 mybase2 &&\n      -\ttest \"$(git config branch.myr3.remote)\" = . &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase never &&\n     -+\tfetch_if_remote_ref_missing o local &&\n     ++\tgit fetch local &&\n       \tgit branch mybase4 &&\n       \tgit branch --track myr4 mybase2 &&\n      -\ttest \"$(git config branch.myr4.remote)\" = . &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase local &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track myr5 local/main &&\n      -\ttest \"$(git config branch.myr5.remote)\" = local &&\n      -\ttest \"$(git config branch.myr5.merge)\" = refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase never &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track myr6 local/main &&\n      -\ttest \"$(git config branch.myr6.remote)\" = local &&\n      -\ttest \"$(git config branch.myr6.merge)\" = refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase remote &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track myr7 local/main &&\n      -\ttest \"$(git config branch.myr7.remote)\" = local &&\n      -\ttest \"$(git config branch.myr7.merge)\" = refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n      +\ttest_config branch.autosetuprebase remote &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track myr8 local/main &&\n      -\ttest \"$(git config branch.myr8.remote)\" = local &&\n      -\ttest \"$(git config branch.myr8.merge)\" = refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_unconfig branch.autosetuprebase &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --track myr9 local/main &&\n      -\ttest \"$(git config branch.myr9.remote)\" = local &&\n      -\ttest \"$(git config branch.myr9.merge)\" = refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n      -\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing o local &&\n     ++\tgit fetch local &&\n       \tgit branch mybase10 &&\n       \tgit branch --track myr10 mybase2 &&\n      -\ttest \"$(git config branch.myr10.remote)\" = . &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr11 mybase2 &&\n      -\ttest \"z$(git config branch.myr11.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr11.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr12 local/main &&\n      -\ttest \"z$(git config branch.myr12.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr12.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase never &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr13 mybase2 &&\n      -\ttest \"z$(git config branch.myr13.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr13.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase local &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr14 mybase2 &&\n      -\ttest \"z$(git config branch.myr14.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr14.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase remote &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr15 mybase2 &&\n      -\ttest \"z$(git config branch.myr15.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr15.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase always &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr16 mybase2 &&\n      -\ttest \"z$(git config branch.myr16.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr16.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase never &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr17 local/main &&\n      -\ttest \"z$(git config branch.myr17.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr17.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase local &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr18 local/main &&\n      -\ttest \"z$(git config branch.myr18.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr18.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase remote &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr19 local/main &&\n      -\ttest \"z$(git config branch.myr19.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr19.merge)\" = z &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      -\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n      +\ttest_config branch.autosetuprebase always &&\n      +\ttest_set_remote local . &&\n     -+\tfetch_if_remote_ref_missing main local &&\n     ++\tgit fetch local &&\n       \tgit branch --no-track myr20 local/main &&\n      -\ttest \"z$(git config branch.myr20.remote)\" = z &&\n      -\ttest \"z$(git config branch.myr20.merge)\" = z &&\n\n\n t/t3200-branch.sh | 439 +++++++++++++++++++++-------------------------\n 1 file changed, 203 insertions(+), 236 deletions(-)\n\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 1bc3795847d..30292d89f2d 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -11,6 +11,11 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-rebase.sh\n \n+test_set_remote () {\n+\ttest_config \"remote.$1.url\" \"$2\" &&\n+\ttest_config \"remote.$1.fetch\" \"${3:-\"refs/heads/*:refs/remotes/$1/*\"}\"\n+}\n+\n test_expect_success 'prepare a trivial repository' '\n \techo Hello >A &&\n \tgit update-index --add A &&\n@@ -372,11 +377,9 @@ EOF\n '\n \n test_expect_success 'git branch with column.*' '\n-\tgit config column.ui column &&\n-\tgit config column.branch \"dense\" &&\n+\ttest_config column.ui column &&\n+\ttest_config column.branch \"dense\" &&\n \tCOLUMNS=80 git branch >actual &&\n-\tgit config --unset column.branch &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c   bam   foo   l   * main   n     o/p   r\n   abc     bar   j/k   m/m   mb     o/o   q     topic\n@@ -389,9 +392,8 @@ test_expect_success 'git branch --column -v should fail' '\n '\n \n test_expect_success 'git branch -v with column.ui ignored' '\n-\tgit config column.ui column &&\n+\ttest_config column.ui column &&\n \tCOLUMNS=80 git branch -v | cut -c -8 | sed \"s/ *$//\" >actual &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c\n   abc\n@@ -435,7 +437,7 @@ test_expect_success 'git branch -m s/s s should work when s/t is deleted' '\n '\n \n test_expect_success 'config information was renamed, too' '\n-\ttest $(git config branch.s.dummy) = Hello &&\n+\ttest_cmp_config Hello branch.s.dummy &&\n \ttest_must_fail git config branch.s/s.dummy\n '\n \n@@ -493,63 +495,57 @@ test_expect_success 'git branch --copy dumps usage' '\n test_expect_success 'git branch -c d e should work' '\n \tgit branch --create-reflog d &&\n \tgit reflog exists refs/heads/d &&\n-\tgit config branch.d.dummy Hello &&\n+\ttest_config branch.d.dummy Hello &&\n \tgit branch -c d e &&\n \tgit reflog exists refs/heads/d &&\n \tgit reflog exists refs/heads/e &&\n-\techo Hello >expect &&\n-\tgit config branch.e.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.d.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.e.dummy &&\n+\ttest_cmp_config Hello branch.d.dummy\n '\n \n test_expect_success 'git branch --copy is a synonym for -c' '\n \tgit branch --create-reflog copy &&\n \tgit reflog exists refs/heads/copy &&\n-\tgit config branch.copy.dummy Hello &&\n+\ttest_config branch.copy.dummy Hello &&\n \tgit branch --copy copy copy-to &&\n \tgit reflog exists refs/heads/copy &&\n \tgit reflog exists refs/heads/copy-to &&\n-\techo Hello >expect &&\n-\tgit config branch.copy.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.copy-to.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.copy.dummy &&\n+\ttest_cmp_config Hello branch.copy-to.dummy\n '\n \n test_expect_success 'git branch -c ee ef should copy ee to create branch ef' '\n \tgit checkout -b ee &&\n \tgit reflog exists refs/heads/ee &&\n-\tgit config branch.ee.dummy Hello &&\n+\ttest_config branch.ee.dummy Hello &&\n \tgit branch -c ee ef &&\n \tgit reflog exists refs/heads/ee &&\n \tgit reflog exists refs/heads/ef &&\n-\ttest $(git config branch.ee.dummy) = Hello &&\n-\ttest $(git config branch.ef.dummy) = Hello &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = ee\n+\ttest_cmp_config Hello branch.ee.dummy &&\n+\ttest_cmp_config Hello branch.ef.dummy &&\n+\techo ee >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'git branch -c f/f g/g should work' '\n \tgit branch --create-reflog f/f &&\n \tgit reflog exists refs/heads/f/f &&\n-\tgit config branch.f/f.dummy Hello &&\n+\ttest_config branch.f/f.dummy Hello &&\n \tgit branch -c f/f g/g &&\n \tgit reflog exists refs/heads/f/f &&\n \tgit reflog exists refs/heads/g/g &&\n-\ttest $(git config branch.f/f.dummy) = Hello &&\n-\ttest $(git config branch.g/g.dummy) = Hello\n+\ttest_cmp_config Hello branch.f/f.dummy &&\n+\ttest_cmp_config Hello branch.g/g.dummy\n '\n \n test_expect_success 'git branch -c m2 m2 should work' '\n \tgit branch --create-reflog m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\tgit config branch.m2.dummy Hello &&\n+\ttest_config branch.m2.dummy Hello &&\n \tgit branch -c m2 m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\ttest $(git config branch.m2.dummy) = Hello\n+\ttest_cmp_config Hello branch.m2.dummy\n '\n \n test_expect_success 'git branch -c zz zz/zz should fail' '\n@@ -619,15 +615,15 @@ test_expect_success 'git branch -C main5 main5 should work when main is checked\n test_expect_success 'git branch -C ab cd should overwrite existing config for cd' '\n \tgit branch --create-reflog cd &&\n \tgit reflog exists refs/heads/cd &&\n-\tgit config branch.cd.dummy CD &&\n+\ttest_config branch.cd.dummy CD &&\n \tgit branch --create-reflog ab &&\n \tgit reflog exists refs/heads/ab &&\n-\tgit config branch.ab.dummy AB &&\n+\ttest_config branch.ab.dummy AB &&\n \tgit branch -C ab cd &&\n \tgit reflog exists refs/heads/ab &&\n \tgit reflog exists refs/heads/cd &&\n-\ttest $(git config branch.ab.dummy) = AB &&\n-\ttest $(git config branch.cd.dummy) = AB\n+\ttest_cmp_config AB branch.ab.dummy &&\n+\ttest_cmp_config AB branch.cd.dummy\n '\n \n test_expect_success 'git branch -c correctly copies multiple config sections' '\n@@ -761,75 +757,67 @@ test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '\n '\n \n test_expect_success 'test tracking setup via --track' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track my1 local/main &&\n-\ttest $(git config branch.my1.remote) = local &&\n-\ttest $(git config branch.my1.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my1.remote &&\n+\ttest_cmp_config refs/heads/main branch.my1.merge\n '\n \n test_expect_success 'test tracking setup (non-wildcard, matching)' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/main:refs/remotes/local/main &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . refs/heads/main:refs/remotes/local/main &&\n+\tgit fetch local &&\n \tgit branch --track my4 local/main &&\n-\ttest $(git config branch.my4.remote) = local &&\n-\ttest $(git config branch.my4.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my4.remote &&\n+\ttest_cmp_config refs/heads/main branch.my4.merge\n '\n \n test_expect_success 'tracking setup fails on non-matching refspec' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n-\tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n+\ttest_config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n \ttest_must_fail git branch --track my5 local/main &&\n \ttest_must_fail git config branch.my5.remote &&\n \ttest_must_fail git config branch.my5.merge\n '\n \n test_expect_success 'test tracking setup via config' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch my3 local/main &&\n-\ttest $(git config branch.my3.remote) = local &&\n-\ttest $(git config branch.my3.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my3.remote &&\n+\ttest_cmp_config refs/heads/main branch.my3.merge\n '\n \n test_expect_success 'test overriding tracking setup via --no-track' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track my2 local/main &&\n-\tgit config branch.autosetupmerge false &&\n-\t! test \"$(git config branch.my2.remote)\" = local &&\n-\t! test \"$(git config branch.my2.merge)\" = refs/heads/main\n+\t! test_cmp_config local branch.my2.remote &&\n+\t! test_cmp_config refs/heads/main branch.my2.merge\n '\n \n test_expect_success 'no tracking without .fetch entries' '\n-\tgit config branch.autosetupmerge true &&\n+\ttest_config branch.autosetupmerge true &&\n \tgit branch my6 s &&\n-\tgit config branch.autosetupmerge false &&\n-\ttest -z \"$(git config branch.my6.remote)\" &&\n-\ttest -z \"$(git config branch.my6.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my6.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my6.merge\n '\n \n test_expect_success 'test tracking setup via --track but deeper' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track my7 local/o/o &&\n-\ttest \"$(git config branch.my7.remote)\" = local &&\n-\ttest \"$(git config branch.my7.merge)\" = refs/heads/o/o\n+\ttest_cmp_config local branch.my7.remote &&\n+\ttest_cmp_config refs/heads/o/o branch.my7.merge\n '\n \n test_expect_success 'test deleting branch deletes branch config' '\n \tgit branch -d my7 &&\n-\ttest -z \"$(git config branch.my7.remote)\" &&\n-\ttest -z \"$(git config branch.my7.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my7.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my7.merge\n '\n \n test_expect_success 'test deleting branch without config' '\n@@ -850,14 +838,15 @@ test_expect_success 'deleting currently checked out branch fails' '\n \n test_expect_success 'test --track without .fetch entries' '\n \tgit branch --track my8 &&\n-\ttest \"$(git config branch.my8.remote)\" &&\n-\ttest \"$(git config branch.my8.merge)\"\n+\tgit config branch.my8.remote >out &&\n+\ttest -s out &&\n+\tgit config branch.my8.merge >out &&\n+\ttest -s out\n '\n \n test_expect_success 'branch from non-branch HEAD w/autosetupmerge=always' '\n-\tgit config branch.autosetupmerge always &&\n-\tgit branch my9 HEAD^ &&\n-\tgit config branch.autosetupmerge false\n+\ttest_config branch.autosetupmerge always &&\n+\tgit branch my9 HEAD^\n '\n \n test_expect_success 'branch from non-branch HEAD w/--track causes failure' '\n@@ -913,16 +902,16 @@ test_expect_success 'use --set-upstream-to modify HEAD' '\n \ttest_config branch.main.merge foo &&\n \tgit branch my12 &&\n \tgit branch --set-upstream-to my12 &&\n-\ttest \"$(git config branch.main.remote)\" = \".\" &&\n-\ttest \"$(git config branch.main.merge)\" = \"refs/heads/my12\"\n+\ttest_cmp_config \".\" branch.main.remote &&\n+\ttest_cmp_config \"refs/heads/my12\" branch.main.merge\n '\n \n test_expect_success 'use --set-upstream-to modify a particular branch' '\n \tgit branch my13 &&\n \tgit branch --set-upstream-to main my13 &&\n \ttest_when_finished \"git branch --unset-upstream my13\" &&\n-\ttest \"$(git config branch.my13.remote)\" = \".\" &&\n-\ttest \"$(git config branch.my13.merge)\" = \"refs/heads/main\"\n+\ttest_cmp_config \".\" branch.my13.remote &&\n+\ttest_cmp_config \"refs/heads/main\" branch.my13.merge\n '\n \n test_expect_success '--unset-upstream should fail if given a non-existent branch' '\n@@ -1003,273 +992,251 @@ test_expect_success 'git checkout -b g/h/i -l should create a branch and a log'\n \n test_expect_success 'checkout -b makes reflog by default' '\n \tgit checkout main &&\n-\tgit config --unset core.logAllRefUpdates &&\n+\ttest_unconfig core.logAllRefUpdates &&\n \tgit checkout -b alpha &&\n \tgit rev-parse --verify alpha@{0}\n '\n \n test_expect_success 'checkout -b does not make reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n-\tgit config core.logAllRefUpdates false &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -b beta &&\n \ttest_must_fail git rev-parse --verify beta@{0}\n '\n \n test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -lb gamma &&\n-\tgit config --unset core.logAllRefUpdates &&\n \tgit rev-parse --verify gamma@{0}\n '\n \n test_expect_success 'avoid ambiguous track' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.ambi1.url lalala &&\n-\tgit config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&\n-\tgit config remote.ambi2.url lilili &&\n-\tgit config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote ambi1 lalala refs/heads/lalala:refs/heads/main &&\n+\ttest_set_remote ambi2 lilili refs/heads/lilili:refs/heads/main &&\n \ttest_must_fail git branch all1 main &&\n-\ttest -z \"$(git config branch.all1.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.all1.merge\n '\n \n test_expect_success 'autosetuprebase local on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tgit fetch local &&\n \tgit branch mybase &&\n \tgit branch --track myr1 mybase &&\n-\ttest \"$(git config branch.myr1.remote)\" = . &&\n-\ttest \"$(git config branch.myr1.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr1.rebase)\" = true\n+\ttest_cmp_config . branch.myr1.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr1.merge &&\n+\ttest_cmp_config true branch.myr1.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase always &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase always &&\n+\tgit fetch local &&\n \tgit branch mybase2 &&\n \tgit branch --track myr2 mybase &&\n-\ttest \"$(git config branch.myr2.remote)\" = . &&\n-\ttest \"$(git config branch.myr2.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr2.rebase)\" = true\n+\ttest_cmp_config . branch.myr2.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr2.merge &&\n+\ttest_cmp_config true branch.myr2.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch mybase3 &&\n \tgit branch --track myr3 mybase2 &&\n-\ttest \"$(git config branch.myr3.remote)\" = . &&\n-\ttest \"$(git config branch.myr3.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr3.rebase)\" = true\n+\ttest_cmp_config . branch.myr3.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr3.merge &&\n+\t! test_cmp_config true branch.myr3.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tgit fetch local &&\n \tgit branch mybase4 &&\n \tgit branch --track myr4 mybase2 &&\n-\ttest \"$(git config branch.myr4.remote)\" = . &&\n-\ttest \"$(git config branch.myr4.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr4.rebase)\" = true\n+\ttest_cmp_config . branch.myr4.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr4.merge &&\n+\t! test_cmp_config true branch.myr4.rebase\n '\n \n test_expect_success 'autosetuprebase local on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tgit fetch local &&\n \tgit branch --track myr5 local/main &&\n-\ttest \"$(git config branch.myr5.remote)\" = local &&\n-\ttest \"$(git config branch.myr5.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr5.rebase)\" = true\n+\ttest_cmp_config local branch.myr5.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr5.merge &&\n+\t! test_cmp_config true branch.myr5.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tgit fetch local &&\n \tgit branch --track myr6 local/main &&\n-\ttest \"$(git config branch.myr6.remote)\" = local &&\n-\ttest \"$(git config branch.myr6.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr6.rebase)\" = true\n+\ttest_cmp_config local branch.myr6.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr6.merge &&\n+\t! test_cmp_config true branch.myr6.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch --track myr7 local/main &&\n-\ttest \"$(git config branch.myr7.remote)\" = local &&\n-\ttest \"$(git config branch.myr7.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr7.rebase)\" = true\n+\ttest_cmp_config local branch.myr7.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr7.merge &&\n+\ttest_cmp_config true branch.myr7.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch --track myr8 local/main &&\n-\ttest \"$(git config branch.myr8.remote)\" = local &&\n-\ttest \"$(git config branch.myr8.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr8.rebase)\" = true\n+\ttest_cmp_config local branch.myr8.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr8.merge &&\n+\ttest_cmp_config true branch.myr8.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' '\n-\tgit config --unset branch.autosetuprebase &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_unconfig branch.autosetuprebase &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track myr9 local/main &&\n-\ttest \"$(git config branch.myr9.remote)\" = local &&\n-\ttest \"$(git config branch.myr9.merge)\" = refs/heads/main &&\n-\ttest \"z$(git config branch.myr9.rebase)\" = z\n+\ttest_cmp_config local branch.myr9.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr9.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr9.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch mybase10 &&\n \tgit branch --track myr10 mybase2 &&\n-\ttest \"$(git config branch.myr10.remote)\" = . &&\n-\ttest \"$(git config branch.myr10.merge)\" = refs/heads/mybase2 &&\n-\ttest \"z$(git config branch.myr10.rebase)\" = z\n+\ttest_cmp_config . branch.myr10.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr10.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr10.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr11 mybase2 &&\n-\ttest \"z$(git config branch.myr11.remote)\" = z &&\n-\ttest \"z$(git config branch.myr11.merge)\" = z &&\n-\ttest \"z$(git config branch.myr11.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr12 local/main &&\n-\ttest \"z$(git config branch.myr12.remote)\" = z &&\n-\ttest \"z$(git config branch.myr12.merge)\" = z &&\n-\ttest \"z$(git config branch.myr12.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked local branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr13 mybase2 &&\n-\ttest \"z$(git config branch.myr13.remote)\" = z &&\n-\ttest \"z$(git config branch.myr13.merge)\" = z &&\n-\ttest \"z$(git config branch.myr13.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked local branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr14 mybase2 &&\n-\ttest \"z$(git config branch.myr14.remote)\" = z &&\n-\ttest \"z$(git config branch.myr14.merge)\" = z &&\n-\ttest \"z$(git config branch.myr14.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked local branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr15 mybase2 &&\n-\ttest \"z$(git config branch.myr15.remote)\" = z &&\n-\ttest \"z$(git config branch.myr15.merge)\" = z &&\n-\ttest \"z$(git config branch.myr15.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked local branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr16 mybase2 &&\n-\ttest \"z$(git config branch.myr16.remote)\" = z &&\n-\ttest \"z$(git config branch.myr16.merge)\" = z &&\n-\ttest \"z$(git config branch.myr16.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked remote branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr17 local/main &&\n-\ttest \"z$(git config branch.myr17.remote)\" = z &&\n-\ttest \"z$(git config branch.myr17.merge)\" = z &&\n-\ttest \"z$(git config branch.myr17.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked remote branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr18 local/main &&\n-\ttest \"z$(git config branch.myr18.remote)\" = z &&\n-\ttest \"z$(git config branch.myr18.merge)\" = z &&\n-\ttest \"z$(git config branch.myr18.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked remote branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr19 local/main &&\n-\ttest \"z$(git config branch.myr19.remote)\" = z &&\n-\ttest \"z$(git config branch.myr19.merge)\" = z &&\n-\ttest \"z$(git config branch.myr19.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked remote branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr20 local/main &&\n-\ttest \"z$(git config branch.myr20.remote)\" = z &&\n-\ttest \"z$(git config branch.myr20.merge)\" = z &&\n-\ttest \"z$(git config branch.myr20.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.rebase\n '\n \n test_expect_success 'autosetuprebase always on detached HEAD' '\n-\tgit config branch.autosetupmerge always &&\n+\ttest_config branch.autosetupmerge always &&\n \ttest_when_finished git checkout main &&\n \tgit checkout HEAD^0 &&\n \tgit branch my11 &&\n-\ttest -z \"$(git config branch.my11.remote)\" &&\n-\ttest -z \"$(git config branch.my11.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my11.rebase\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (bad value)' '\n-\tgit config branch.autosetuprebase garbage &&\n+\ttest_config branch.autosetuprebase garbage &&\n \ttest_must_fail git branch\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n-\tgit config --unset branch.autosetuprebase &&\n+\ttest_unconfig branch.autosetuprebase &&\n \techo \"[branch] autosetuprebase\" >>.git/config &&\n \ttest_must_fail git branch &&\n \tgit config --unset branch.autosetuprebase\n@@ -1277,7 +1244,7 @@ test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n \n test_expect_success 'attempt to delete a branch without base and unmerged to HEAD' '\n \tgit checkout my9 &&\n-\tgit config --unset branch.my8.merge &&\n+\ttest_unconfig branch.my8.merge &&\n \ttest_must_fail git branch -d my8\n '\n \n@@ -1285,7 +1252,7 @@ test_expect_success 'attempt to delete a branch merged to its base' '\n \t# we are on my9 which is the initial commit; traditionally\n \t# we would not have allowed deleting my8 that is not merged\n \t# to my9, but it is set to track main that already has my8\n-\tgit config branch.my8.merge refs/heads/main &&\n+\ttest_config branch.my8.merge refs/heads/main &&\n \tgit branch -d my8\n '\n \n@@ -1397,8 +1364,8 @@ test_expect_success 'tracking with unexpected .fetch refspec' '\n \t\tgit config remote.c.fetch \"+refs/remotes/*:refs/remotes/*\" &&\n \t\tgit fetch c &&\n \t\tgit branch --track local/a/main remotes/a/main &&\n-\t\ttest \"$(git config branch.local/a/main.remote)\" = \"c\" &&\n-\t\ttest \"$(git config branch.local/a/main.merge)\" = \"refs/remotes/a/main\" &&\n+\t\ttest_cmp_config \"c\" branch.local/a/main.remote &&\n+\t\ttest_cmp_config \"refs/remotes/a/main\" branch.local/a/main.merge &&\n \t\tgit rev-parse --verify a >expect &&\n \t\tgit rev-parse --verify local/a/main >actual &&\n \t\ttest_cmp expect actual\n\nbase-commit: 4c53a8c20f8984adb226293a3ffd7b88c3f4ac1a\n-- \ngitgitgadget\n"},{"id":"454685","messageId":"pull.1182.v3.git.1651344174050.gitgitgadget@gmail.com","threadId":"57589","inReplyTo":"pull.1182.v2.git.1647995031417.gitgitgadget@gmail.com","subject":"[PATCH v3] t3200: fix antipatterns in existing branch tests","fromName":"Tao Klerks via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2022-04-30T18:42:53Z","receivedAt":"2022-04-30T18:43:03Z","isPatch":true,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"From: Tao Klerks <tao@klerks.biz>\n\nFix issues in t3200 branch tests that, if copied, might catch new\ncontributors out:\n\nUse test_config to show that config state is not being intentionally\nleft to spill over into other tests.\n\nUse test_cmp_config instead of git config in subshells, so that\ngit's error code is not lost if/when an unexpected error occurs.\n\nUse output redirection and later content checking instead of\nsubshells, so that git's error code is not lost if/when an\nunexpected error occurs.\n\nEliminate local-fetch-avoiding optimization as it is error-prone (it\nis easy to check the wrong thing), hides segfaults, and yields only\na marginal performance improvement given the fetch is local.\n\nIntroduce local helper test_set_remote to simplify the common local\npattern of setting up a remote via config.\n\nSigned-off-by: Tao Klerks <tao@klerks.biz>\n---\n    t3200: fix antipatterns in existing branch tests\n    \n    This is a cleanup of the branch tests following a case where I was\n    adding some, and did substantially the wrong thing by following existing\n    examples.\n    \n    Changes in V3:\n    \n     * rebased onto recent master (with some conflict resolution)\n    \n    Resending for rebase and also because there have been no comments in a\n    long time.\n\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-1182%2FTaoK%2Fcleanup-t3200-tests-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-1182/TaoK/cleanup-t3200-tests-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/1182\n\nRange-diff vs v2:\n\n 1:  e4addb910f7 ! 1:  d49a230952e t3200: fix antipatterns in existing branch tests\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n       \tgit rev-parse --verify gamma@{0}\n       '\n       \n     - test_expect_success 'avoid ambiguous track' '\n     + test_expect_success 'avoid ambiguous track and advise' '\n      -\tgit config branch.autosetupmerge true &&\n      -\tgit config remote.ambi1.url lalala &&\n      -\tgit config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&\n     @@ t/t3200-branch.sh: test_expect_success 'git checkout -b g/h/i -l should create a\n      +\ttest_config branch.autosetupmerge true &&\n      +\ttest_set_remote ambi1 lalala refs/heads/lalala:refs/heads/main &&\n      +\ttest_set_remote ambi2 lilili refs/heads/lilili:refs/heads/main &&\n     - \ttest_must_fail git branch all1 main &&\n     + \tcat <<-EOF >expected &&\n     + \tfatal: not tracking: ambiguous information for ref '\\''refs/heads/main'\\''\n     + \thint: There are multiple remotes whose fetch refspecs map to the remote\n     +@@ t/t3200-branch.sh: test_expect_success 'avoid ambiguous track and advise' '\n     + \tEOF\n     + \ttest_must_fail git branch all1 main 2>actual &&\n     + \ttest_cmp expected actual &&\n      -\ttest -z \"$(git config branch.all1.merge)\"\n      +\ttest_cmp_config \"\" --default \"\" branch.all1.merge\n       '\n\n\n t/t3200-branch.sh | 439 +++++++++++++++++++++-------------------------\n 1 file changed, 203 insertions(+), 236 deletions(-)\n\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex e12db593615..88cbc866ab6 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -11,6 +11,11 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-rebase.sh\n \n+test_set_remote () {\n+\ttest_config \"remote.$1.url\" \"$2\" &&\n+\ttest_config \"remote.$1.fetch\" \"${3:-\"refs/heads/*:refs/remotes/$1/*\"}\"\n+}\n+\n test_expect_success 'prepare a trivial repository' '\n \techo Hello >A &&\n \tgit update-index --add A &&\n@@ -389,11 +394,9 @@ EOF\n '\n \n test_expect_success 'git branch with column.*' '\n-\tgit config column.ui column &&\n-\tgit config column.branch \"dense\" &&\n+\ttest_config column.ui column &&\n+\ttest_config column.branch \"dense\" &&\n \tCOLUMNS=80 git branch >actual &&\n-\tgit config --unset column.branch &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c   bam   foo   l   * main   n     o/p   r\n   abc     bar   j/k   m/m   mb     o/o   q     topic\n@@ -406,9 +409,8 @@ test_expect_success 'git branch --column -v should fail' '\n '\n \n test_expect_success 'git branch -v with column.ui ignored' '\n-\tgit config column.ui column &&\n+\ttest_config column.ui column &&\n \tCOLUMNS=80 git branch -v | cut -c -8 | sed \"s/ *$//\" >actual &&\n-\tgit config --unset column.ui &&\n \tcat >expect <<\\EOF &&\n   a/b/c\n   abc\n@@ -452,7 +454,7 @@ test_expect_success 'git branch -m s/s s should work when s/t is deleted' '\n '\n \n test_expect_success 'config information was renamed, too' '\n-\ttest $(git config branch.s.dummy) = Hello &&\n+\ttest_cmp_config Hello branch.s.dummy &&\n \ttest_must_fail git config branch.s/s.dummy\n '\n \n@@ -510,63 +512,57 @@ test_expect_success 'git branch --copy dumps usage' '\n test_expect_success 'git branch -c d e should work' '\n \tgit branch --create-reflog d &&\n \tgit reflog exists refs/heads/d &&\n-\tgit config branch.d.dummy Hello &&\n+\ttest_config branch.d.dummy Hello &&\n \tgit branch -c d e &&\n \tgit reflog exists refs/heads/d &&\n \tgit reflog exists refs/heads/e &&\n-\techo Hello >expect &&\n-\tgit config branch.e.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.d.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.e.dummy &&\n+\ttest_cmp_config Hello branch.d.dummy\n '\n \n test_expect_success 'git branch --copy is a synonym for -c' '\n \tgit branch --create-reflog copy &&\n \tgit reflog exists refs/heads/copy &&\n-\tgit config branch.copy.dummy Hello &&\n+\ttest_config branch.copy.dummy Hello &&\n \tgit branch --copy copy copy-to &&\n \tgit reflog exists refs/heads/copy &&\n \tgit reflog exists refs/heads/copy-to &&\n-\techo Hello >expect &&\n-\tgit config branch.copy.dummy >actual &&\n-\ttest_cmp expect actual &&\n-\techo Hello >expect &&\n-\tgit config branch.copy-to.dummy >actual &&\n-\ttest_cmp expect actual\n+\ttest_cmp_config Hello branch.copy.dummy &&\n+\ttest_cmp_config Hello branch.copy-to.dummy\n '\n \n test_expect_success 'git branch -c ee ef should copy ee to create branch ef' '\n \tgit checkout -b ee &&\n \tgit reflog exists refs/heads/ee &&\n-\tgit config branch.ee.dummy Hello &&\n+\ttest_config branch.ee.dummy Hello &&\n \tgit branch -c ee ef &&\n \tgit reflog exists refs/heads/ee &&\n \tgit reflog exists refs/heads/ef &&\n-\ttest $(git config branch.ee.dummy) = Hello &&\n-\ttest $(git config branch.ef.dummy) = Hello &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = ee\n+\ttest_cmp_config Hello branch.ee.dummy &&\n+\ttest_cmp_config Hello branch.ef.dummy &&\n+\techo ee >expect &&\n+\tgit rev-parse --abbrev-ref HEAD >actual &&\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'git branch -c f/f g/g should work' '\n \tgit branch --create-reflog f/f &&\n \tgit reflog exists refs/heads/f/f &&\n-\tgit config branch.f/f.dummy Hello &&\n+\ttest_config branch.f/f.dummy Hello &&\n \tgit branch -c f/f g/g &&\n \tgit reflog exists refs/heads/f/f &&\n \tgit reflog exists refs/heads/g/g &&\n-\ttest $(git config branch.f/f.dummy) = Hello &&\n-\ttest $(git config branch.g/g.dummy) = Hello\n+\ttest_cmp_config Hello branch.f/f.dummy &&\n+\ttest_cmp_config Hello branch.g/g.dummy\n '\n \n test_expect_success 'git branch -c m2 m2 should work' '\n \tgit branch --create-reflog m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\tgit config branch.m2.dummy Hello &&\n+\ttest_config branch.m2.dummy Hello &&\n \tgit branch -c m2 m2 &&\n \tgit reflog exists refs/heads/m2 &&\n-\ttest $(git config branch.m2.dummy) = Hello\n+\ttest_cmp_config Hello branch.m2.dummy\n '\n \n test_expect_success 'git branch -c zz zz/zz should fail' '\n@@ -636,15 +632,15 @@ test_expect_success 'git branch -C main5 main5 should work when main is checked\n test_expect_success 'git branch -C ab cd should overwrite existing config for cd' '\n \tgit branch --create-reflog cd &&\n \tgit reflog exists refs/heads/cd &&\n-\tgit config branch.cd.dummy CD &&\n+\ttest_config branch.cd.dummy CD &&\n \tgit branch --create-reflog ab &&\n \tgit reflog exists refs/heads/ab &&\n-\tgit config branch.ab.dummy AB &&\n+\ttest_config branch.ab.dummy AB &&\n \tgit branch -C ab cd &&\n \tgit reflog exists refs/heads/ab &&\n \tgit reflog exists refs/heads/cd &&\n-\ttest $(git config branch.ab.dummy) = AB &&\n-\ttest $(git config branch.cd.dummy) = AB\n+\ttest_cmp_config AB branch.ab.dummy &&\n+\ttest_cmp_config AB branch.cd.dummy\n '\n \n test_expect_success 'git branch -c correctly copies multiple config sections' '\n@@ -778,75 +774,67 @@ test_expect_success SYMLINKS 'git branch -m with symlinked .git/refs' '\n '\n \n test_expect_success 'test tracking setup via --track' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track my1 local/main &&\n-\ttest $(git config branch.my1.remote) = local &&\n-\ttest $(git config branch.my1.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my1.remote &&\n+\ttest_cmp_config refs/heads/main branch.my1.merge\n '\n \n test_expect_success 'test tracking setup (non-wildcard, matching)' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/main:refs/remotes/local/main &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . refs/heads/main:refs/remotes/local/main &&\n+\tgit fetch local &&\n \tgit branch --track my4 local/main &&\n-\ttest $(git config branch.my4.remote) = local &&\n-\ttest $(git config branch.my4.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my4.remote &&\n+\ttest_cmp_config refs/heads/main branch.my4.merge\n '\n \n test_expect_success 'tracking setup fails on non-matching refspec' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n-\tgit config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n+\ttest_config remote.local.fetch refs/heads/s:refs/remotes/local/s &&\n \ttest_must_fail git branch --track my5 local/main &&\n \ttest_must_fail git config branch.my5.remote &&\n \ttest_must_fail git config branch.my5.merge\n '\n \n test_expect_success 'test tracking setup via config' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch my3 local/main &&\n-\ttest $(git config branch.my3.remote) = local &&\n-\ttest $(git config branch.my3.merge) = refs/heads/main\n+\ttest_cmp_config local branch.my3.remote &&\n+\ttest_cmp_config refs/heads/main branch.my3.merge\n '\n \n test_expect_success 'test overriding tracking setup via --no-track' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track my2 local/main &&\n-\tgit config branch.autosetupmerge false &&\n-\t! test \"$(git config branch.my2.remote)\" = local &&\n-\t! test \"$(git config branch.my2.merge)\" = refs/heads/main\n+\t! test_cmp_config local branch.my2.remote &&\n+\t! test_cmp_config refs/heads/main branch.my2.merge\n '\n \n test_expect_success 'no tracking without .fetch entries' '\n-\tgit config branch.autosetupmerge true &&\n+\ttest_config branch.autosetupmerge true &&\n \tgit branch my6 s &&\n-\tgit config branch.autosetupmerge false &&\n-\ttest -z \"$(git config branch.my6.remote)\" &&\n-\ttest -z \"$(git config branch.my6.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my6.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my6.merge\n '\n \n test_expect_success 'test tracking setup via --track but deeper' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track my7 local/o/o &&\n-\ttest \"$(git config branch.my7.remote)\" = local &&\n-\ttest \"$(git config branch.my7.merge)\" = refs/heads/o/o\n+\ttest_cmp_config local branch.my7.remote &&\n+\ttest_cmp_config refs/heads/o/o branch.my7.merge\n '\n \n test_expect_success 'test deleting branch deletes branch config' '\n \tgit branch -d my7 &&\n-\ttest -z \"$(git config branch.my7.remote)\" &&\n-\ttest -z \"$(git config branch.my7.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my7.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my7.merge\n '\n \n test_expect_success 'test deleting branch without config' '\n@@ -867,14 +855,15 @@ test_expect_success 'deleting currently checked out branch fails' '\n \n test_expect_success 'test --track without .fetch entries' '\n \tgit branch --track my8 &&\n-\ttest \"$(git config branch.my8.remote)\" &&\n-\ttest \"$(git config branch.my8.merge)\"\n+\tgit config branch.my8.remote >out &&\n+\ttest -s out &&\n+\tgit config branch.my8.merge >out &&\n+\ttest -s out\n '\n \n test_expect_success 'branch from non-branch HEAD w/autosetupmerge=always' '\n-\tgit config branch.autosetupmerge always &&\n-\tgit branch my9 HEAD^ &&\n-\tgit config branch.autosetupmerge false\n+\ttest_config branch.autosetupmerge always &&\n+\tgit branch my9 HEAD^\n '\n \n test_expect_success 'branch from non-branch HEAD w/--track causes failure' '\n@@ -930,16 +919,16 @@ test_expect_success 'use --set-upstream-to modify HEAD' '\n \ttest_config branch.main.merge foo &&\n \tgit branch my12 &&\n \tgit branch --set-upstream-to my12 &&\n-\ttest \"$(git config branch.main.remote)\" = \".\" &&\n-\ttest \"$(git config branch.main.merge)\" = \"refs/heads/my12\"\n+\ttest_cmp_config \".\" branch.main.remote &&\n+\ttest_cmp_config \"refs/heads/my12\" branch.main.merge\n '\n \n test_expect_success 'use --set-upstream-to modify a particular branch' '\n \tgit branch my13 &&\n \tgit branch --set-upstream-to main my13 &&\n \ttest_when_finished \"git branch --unset-upstream my13\" &&\n-\ttest \"$(git config branch.my13.remote)\" = \".\" &&\n-\ttest \"$(git config branch.my13.merge)\" = \"refs/heads/main\"\n+\ttest_cmp_config \".\" branch.my13.remote &&\n+\ttest_cmp_config \"refs/heads/main\" branch.my13.merge\n '\n \n test_expect_success '--unset-upstream should fail if given a non-existent branch' '\n@@ -1020,31 +1009,29 @@ test_expect_success 'git checkout -b g/h/i -l should create a branch and a log'\n \n test_expect_success 'checkout -b makes reflog by default' '\n \tgit checkout main &&\n-\tgit config --unset core.logAllRefUpdates &&\n+\ttest_unconfig core.logAllRefUpdates &&\n \tgit checkout -b alpha &&\n \tgit rev-parse --verify alpha@{0}\n '\n \n test_expect_success 'checkout -b does not make reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n-\tgit config core.logAllRefUpdates false &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -b beta &&\n \ttest_must_fail git rev-parse --verify beta@{0}\n '\n \n test_expect_success 'checkout -b with -l makes reflog when core.logAllRefUpdates = false' '\n \tgit checkout main &&\n+\ttest_config core.logAllRefUpdates false &&\n \tgit checkout -lb gamma &&\n-\tgit config --unset core.logAllRefUpdates &&\n \tgit rev-parse --verify gamma@{0}\n '\n \n test_expect_success 'avoid ambiguous track and advise' '\n-\tgit config branch.autosetupmerge true &&\n-\tgit config remote.ambi1.url lalala &&\n-\tgit config remote.ambi1.fetch refs/heads/lalala:refs/heads/main &&\n-\tgit config remote.ambi2.url lilili &&\n-\tgit config remote.ambi2.fetch refs/heads/lilili:refs/heads/main &&\n+\ttest_config branch.autosetupmerge true &&\n+\ttest_set_remote ambi1 lalala refs/heads/lalala:refs/heads/main &&\n+\ttest_set_remote ambi2 lilili refs/heads/lilili:refs/heads/main &&\n \tcat <<-EOF >expected &&\n \tfatal: not tracking: ambiguous information for ref '\\''refs/heads/main'\\''\n \thint: There are multiple remotes whose fetch refspecs map to the remote\n@@ -1060,247 +1047,227 @@ test_expect_success 'avoid ambiguous track and advise' '\n \tEOF\n \ttest_must_fail git branch all1 main 2>actual &&\n \ttest_cmp expected actual &&\n-\ttest -z \"$(git config branch.all1.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.all1.merge\n '\n \n test_expect_success 'autosetuprebase local on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tgit fetch local &&\n \tgit branch mybase &&\n \tgit branch --track myr1 mybase &&\n-\ttest \"$(git config branch.myr1.remote)\" = . &&\n-\ttest \"$(git config branch.myr1.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr1.rebase)\" = true\n+\ttest_cmp_config . branch.myr1.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr1.merge &&\n+\ttest_cmp_config true branch.myr1.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase always &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase always &&\n+\tgit fetch local &&\n \tgit branch mybase2 &&\n \tgit branch --track myr2 mybase &&\n-\ttest \"$(git config branch.myr2.remote)\" = . &&\n-\ttest \"$(git config branch.myr2.merge)\" = refs/heads/mybase &&\n-\ttest \"$(git config branch.myr2.rebase)\" = true\n+\ttest_cmp_config . branch.myr2.remote &&\n+\ttest_cmp_config refs/heads/mybase branch.myr2.merge &&\n+\ttest_cmp_config true branch.myr2.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch mybase3 &&\n \tgit branch --track myr3 mybase2 &&\n-\ttest \"$(git config branch.myr3.remote)\" = . &&\n-\ttest \"$(git config branch.myr3.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr3.rebase)\" = true\n+\ttest_cmp_config . branch.myr3.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr3.merge &&\n+\t! test_cmp_config true branch.myr3.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tgit fetch local &&\n \tgit branch mybase4 &&\n \tgit branch --track myr4 mybase2 &&\n-\ttest \"$(git config branch.myr4.remote)\" = . &&\n-\ttest \"$(git config branch.myr4.merge)\" = refs/heads/mybase2 &&\n-\t! test \"$(git config branch.myr4.rebase)\" = true\n+\ttest_cmp_config . branch.myr4.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr4.merge &&\n+\t! test_cmp_config true branch.myr4.rebase\n '\n \n test_expect_success 'autosetuprebase local on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase local &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase local &&\n+\tgit fetch local &&\n \tgit branch --track myr5 local/main &&\n-\ttest \"$(git config branch.myr5.remote)\" = local &&\n-\ttest \"$(git config branch.myr5.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr5.rebase)\" = true\n+\ttest_cmp_config local branch.myr5.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr5.merge &&\n+\t! test_cmp_config true branch.myr5.rebase\n '\n \n test_expect_success 'autosetuprebase never on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase never &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase never &&\n+\tgit fetch local &&\n \tgit branch --track myr6 local/main &&\n-\ttest \"$(git config branch.myr6.remote)\" = local &&\n-\ttest \"$(git config branch.myr6.merge)\" = refs/heads/main &&\n-\t! test \"$(git config branch.myr6.rebase)\" = true\n+\ttest_cmp_config local branch.myr6.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr6.merge &&\n+\t! test_cmp_config true branch.myr6.rebase\n '\n \n test_expect_success 'autosetuprebase remote on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch --track myr7 local/main &&\n-\ttest \"$(git config branch.myr7.remote)\" = local &&\n-\ttest \"$(git config branch.myr7.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr7.rebase)\" = true\n+\ttest_cmp_config local branch.myr7.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr7.merge &&\n+\ttest_cmp_config true branch.myr7.rebase\n '\n \n test_expect_success 'autosetuprebase always on a tracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\tgit config branch.autosetuprebase remote &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\ttest_config branch.autosetuprebase remote &&\n+\tgit fetch local &&\n \tgit branch --track myr8 local/main &&\n-\ttest \"$(git config branch.myr8.remote)\" = local &&\n-\ttest \"$(git config branch.myr8.merge)\" = refs/heads/main &&\n-\ttest \"$(git config branch.myr8.rebase)\" = true\n+\ttest_cmp_config local branch.myr8.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr8.merge &&\n+\ttest_cmp_config true branch.myr8.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked remote branch' '\n-\tgit config --unset branch.autosetuprebase &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_unconfig branch.autosetuprebase &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --track myr9 local/main &&\n-\ttest \"$(git config branch.myr9.remote)\" = local &&\n-\ttest \"$(git config branch.myr9.merge)\" = refs/heads/main &&\n-\ttest \"z$(git config branch.myr9.rebase)\" = z\n+\ttest_cmp_config local branch.myr9.remote &&\n+\ttest_cmp_config refs/heads/main branch.myr9.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr9.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on a tracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/o || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch mybase10 &&\n \tgit branch --track myr10 mybase2 &&\n-\ttest \"$(git config branch.myr10.remote)\" = . &&\n-\ttest \"$(git config branch.myr10.merge)\" = refs/heads/mybase2 &&\n-\ttest \"z$(git config branch.myr10.rebase)\" = z\n+\ttest_cmp_config . branch.myr10.remote &&\n+\ttest_cmp_config refs/heads/mybase2 branch.myr10.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr10.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked local branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr11 mybase2 &&\n-\ttest \"z$(git config branch.myr11.remote)\" = z &&\n-\ttest \"z$(git config branch.myr11.merge)\" = z &&\n-\ttest \"z$(git config branch.myr11.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr11.rebase\n '\n \n test_expect_success 'autosetuprebase unconfigured on untracked remote branch' '\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr12 local/main &&\n-\ttest \"z$(git config branch.myr12.remote)\" = z &&\n-\ttest \"z$(git config branch.myr12.merge)\" = z &&\n-\ttest \"z$(git config branch.myr12.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr12.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked local branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr13 mybase2 &&\n-\ttest \"z$(git config branch.myr13.remote)\" = z &&\n-\ttest \"z$(git config branch.myr13.merge)\" = z &&\n-\ttest \"z$(git config branch.myr13.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr13.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked local branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr14 mybase2 &&\n-\ttest \"z$(git config branch.myr14.remote)\" = z &&\n-\ttest \"z$(git config branch.myr14.merge)\" = z &&\n-\ttest \"z$(git config branch.myr14.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr14.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked local branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr15 mybase2 &&\n-\ttest \"z$(git config branch.myr15.remote)\" = z &&\n-\ttest \"z$(git config branch.myr15.merge)\" = z &&\n-\ttest \"z$(git config branch.myr15.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr15.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked local branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr16 mybase2 &&\n-\ttest \"z$(git config branch.myr16.remote)\" = z &&\n-\ttest \"z$(git config branch.myr16.merge)\" = z &&\n-\ttest \"z$(git config branch.myr16.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr16.rebase\n '\n \n test_expect_success 'autosetuprebase never on an untracked remote branch' '\n-\tgit config branch.autosetuprebase never &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase never &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr17 local/main &&\n-\ttest \"z$(git config branch.myr17.remote)\" = z &&\n-\ttest \"z$(git config branch.myr17.merge)\" = z &&\n-\ttest \"z$(git config branch.myr17.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr17.rebase\n '\n \n test_expect_success 'autosetuprebase local on an untracked remote branch' '\n-\tgit config branch.autosetuprebase local &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase local &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr18 local/main &&\n-\ttest \"z$(git config branch.myr18.remote)\" = z &&\n-\ttest \"z$(git config branch.myr18.merge)\" = z &&\n-\ttest \"z$(git config branch.myr18.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr18.rebase\n '\n \n test_expect_success 'autosetuprebase remote on an untracked remote branch' '\n-\tgit config branch.autosetuprebase remote &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase remote &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr19 local/main &&\n-\ttest \"z$(git config branch.myr19.remote)\" = z &&\n-\ttest \"z$(git config branch.myr19.merge)\" = z &&\n-\ttest \"z$(git config branch.myr19.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr19.rebase\n '\n \n test_expect_success 'autosetuprebase always on an untracked remote branch' '\n-\tgit config branch.autosetuprebase always &&\n-\tgit config remote.local.url . &&\n-\tgit config remote.local.fetch refs/heads/*:refs/remotes/local/* &&\n-\t(git show-ref -q refs/remotes/local/main || git fetch local) &&\n+\ttest_config branch.autosetuprebase always &&\n+\ttest_set_remote local . &&\n+\tgit fetch local &&\n \tgit branch --no-track myr20 local/main &&\n-\ttest \"z$(git config branch.myr20.remote)\" = z &&\n-\ttest \"z$(git config branch.myr20.merge)\" = z &&\n-\ttest \"z$(git config branch.myr20.rebase)\" = z\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.merge &&\n+\ttest_cmp_config \"\" --default \"\" branch.myr20.rebase\n '\n \n test_expect_success 'autosetuprebase always on detached HEAD' '\n-\tgit config branch.autosetupmerge always &&\n+\ttest_config branch.autosetupmerge always &&\n \ttest_when_finished git checkout main &&\n \tgit checkout HEAD^0 &&\n \tgit branch my11 &&\n-\ttest -z \"$(git config branch.my11.remote)\" &&\n-\ttest -z \"$(git config branch.my11.merge)\"\n+\ttest_cmp_config \"\" --default \"\" branch.my11.remote &&\n+\ttest_cmp_config \"\" --default \"\" branch.my11.rebase\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (bad value)' '\n-\tgit config branch.autosetuprebase garbage &&\n+\ttest_config branch.autosetuprebase garbage &&\n \ttest_must_fail git branch\n '\n \n test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n-\tgit config --unset branch.autosetuprebase &&\n+\ttest_unconfig branch.autosetuprebase &&\n \techo \"[branch] autosetuprebase\" >>.git/config &&\n \ttest_must_fail git branch &&\n \tgit config --unset branch.autosetuprebase\n@@ -1308,7 +1275,7 @@ test_expect_success 'detect misconfigured autosetuprebase (no value)' '\n \n test_expect_success 'attempt to delete a branch without base and unmerged to HEAD' '\n \tgit checkout my9 &&\n-\tgit config --unset branch.my8.merge &&\n+\ttest_unconfig branch.my8.merge &&\n \ttest_must_fail git branch -d my8\n '\n \n@@ -1316,7 +1283,7 @@ test_expect_success 'attempt to delete a branch merged to its base' '\n \t# we are on my9 which is the initial commit; traditionally\n \t# we would not have allowed deleting my8 that is not merged\n \t# to my9, but it is set to track main that already has my8\n-\tgit config branch.my8.merge refs/heads/main &&\n+\ttest_config branch.my8.merge refs/heads/main &&\n \tgit branch -d my8\n '\n \n@@ -1428,8 +1395,8 @@ test_expect_success 'tracking with unexpected .fetch refspec' '\n \t\tgit config remote.c.fetch \"+refs/remotes/*:refs/remotes/*\" &&\n \t\tgit fetch c &&\n \t\tgit branch --track local/a/main remotes/a/main &&\n-\t\ttest \"$(git config branch.local/a/main.remote)\" = \"c\" &&\n-\t\ttest \"$(git config branch.local/a/main.merge)\" = \"refs/remotes/a/main\" &&\n+\t\ttest_cmp_config \"c\" branch.local/a/main.remote &&\n+\t\ttest_cmp_config \"refs/remotes/a/main\" branch.local/a/main.merge &&\n \t\tgit rev-parse --verify a >expect &&\n \t\tgit rev-parse --verify local/a/main >actual &&\n \t\ttest_cmp expect actual\n\nbase-commit: 0f828332d5ac36fc63b7d8202652efa152809856\n-- \ngitgitgadget\n"},{"id":"454833","messageId":"xmqqh765mcn0.fsf@gitster.g","threadId":"57589","inReplyTo":"pull.1182.v3.git.1651344174050.gitgitgadget@gmail.com","subject":"Re: [PATCH v3] t3200: fix antipatterns in existing branch tests","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2022-05-04T17:27:31Z","receivedAt":"2022-05-04T18:07:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Tao Klerks via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n\n> +test_set_remote () {\n> +\ttest_config \"remote.$1.url\" \"$2\" &&\n> +\ttest_config \"remote.$1.fetch\" \"${3:-\"refs/heads/*:refs/remotes/$1/*\"}\"\n> +}\n> +\n\n> @@ -389,11 +394,9 @@ EOF\n>  '\n>  \n>  test_expect_success 'git branch with column.*' '\n> -\tgit config column.ui column &&\n> -\tgit config column.branch \"dense\" &&\n> +\ttest_config column.ui column &&\n> +\ttest_config column.branch \"dense\" &&\n>  \tCOLUMNS=80 git branch >actual &&\n> -\tgit config --unset column.branch &&\n> -\tgit config --unset column.ui &&\n\nOK these are easy to verify, as we can clearly see that the\nintention is for these two settings to affect no later tests.\n\n> @@ -406,9 +409,8 @@ test_expect_success 'git branch --column -v should fail' '\n>  '\n>  \n>  test_expect_success 'git branch -v with column.ui ignored' '\n> -\tgit config column.ui column &&\n> +\ttest_config column.ui column &&\n>  \tCOLUMNS=80 git branch -v | cut -c -8 | sed \"s/ *$//\" >actual &&\n> -\tgit config --unset column.ui &&\n\nLikewise.\n\n> @@ -452,7 +454,7 @@ test_expect_success 'git branch -m s/s s should work when s/t is deleted' '\n>  '\n>  \n>  test_expect_success 'config information was renamed, too' '\n> -\ttest $(git config branch.s.dummy) = Hello &&\n> +\ttest_cmp_config Hello branch.s.dummy &&\n>  \ttest_must_fail git config branch.s/s.dummy\n>  '\n\nOK.\n\n> @@ -510,63 +512,57 @@ test_expect_success 'git branch --copy dumps usage' '\n>  test_expect_success 'git branch -c d e should work' '\n>  \tgit branch --create-reflog d &&\n>  \tgit reflog exists refs/heads/d &&\n> -\tgit config branch.d.dummy Hello &&\n> +\ttest_config branch.d.dummy Hello &&\n>  \tgit branch -c d e &&\n>  \tgit reflog exists refs/heads/d &&\n>  \tgit reflog exists refs/heads/e &&\n> -\techo Hello >expect &&\n> -\tgit config branch.e.dummy >actual &&\n> -\ttest_cmp expect actual &&\n> -\techo Hello >expect &&\n> -\tgit config branch.d.dummy >actual &&\n> -\ttest_cmp expect actual\n> +\ttest_cmp_config Hello branch.e.dummy &&\n> +\ttest_cmp_config Hello branch.d.dummy\n>  '\n\nThis test used to leave both branch.d.dummy and branch.e.dummy behind\nfor later tests.  Now with this patch, we clean branch.d.dummy\nbecause we use test_config, but branch.e.dummy that was copied by\nsuccessful \"git branch -c\" will still be left.\n\n - It is unforunate that it is impossible to verify that the change\n   in behaviour for branch.d.dummy is correct.  Without checking all\n   the remainder of the test (and no, grepping for branch.d.dummy is\n   not \"checking all the remainder\"---a later \"branch -c d x\" would\n   have created brnach.x.dummy in the original, but with this patch,\n   it would not), which is time consuming, that is.\n\n   I trust you made sure that branch.d.dummy is never used after\n   this test is done---it would have been good to explain it either\n   in the proposed log message or after three-dash that you did\n   check and how to save reviewer bandwidth.\n\n - Are you deliberatly leaving branch.e.dummy uncleaned, or is it a\n   mere oversight?\n\n>  test_expect_success 'git branch --copy is a synonym for -c' '\n>  \tgit branch --create-reflog copy &&\n>  \tgit reflog exists refs/heads/copy &&\n> -\tgit config branch.copy.dummy Hello &&\n> +\ttest_config branch.copy.dummy Hello &&\n>  \tgit branch --copy copy copy-to &&\n>  \tgit reflog exists refs/heads/copy &&\n>  \tgit reflog exists refs/heads/copy-to &&\n> -\techo Hello >expect &&\n> -\tgit config branch.copy.dummy >actual &&\n> -\ttest_cmp expect actual &&\n> -\techo Hello >expect &&\n> -\tgit config branch.copy-to.dummy >actual &&\n> -\ttest_cmp expect actual\n> +\ttest_cmp_config Hello branch.copy.dummy &&\n> +\ttest_cmp_config Hello branch.copy-to.dummy\n>  '\n\nThe same comment for branch.copy.dummy and branch.copy-to.dummy\napplies.\n\nI'll stop here for now.  Thanks for starting this clean-up.\n"},{"id":"455189","messageId":"CAPMMpogxDfmoc_9CnL6x2Hf79BgWDrq=3KfMrbc+xwyo1k=yJQ@mail.gmail.com","threadId":"57589","inReplyTo":"xmqqh765mcn0.fsf@gitster.g","subject":"Re: [PATCH v3] t3200: fix antipatterns in existing branch tests","fromName":"Tao Klerks","fromEmail":"tao@klerks.biz","sentAt":"2022-05-12T05:12:29Z","receivedAt":"2022-05-12T05:12:47Z","isPatch":true,"sender":{"key":"tao@klerks.biz","avatar":"https://avatars.githubusercontent.com/u/531704?v=4"},"body":"On Wed, May 4, 2022 at 7:27 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> \"Tao Klerks via GitGitGadget\" <gitgitgadget@gmail.com> writes:\n>\n>\n> > @@ -510,63 +512,57 @@ test_expect_success 'git branch --copy dumps usage' '\n> >  test_expect_success 'git branch -c d e should work' '\n> >       git branch --create-reflog d &&\n> >       git reflog exists refs/heads/d &&\n> > -     git config branch.d.dummy Hello &&\n> > +     test_config branch.d.dummy Hello &&\n> >       git branch -c d e &&\n> >       git reflog exists refs/heads/d &&\n> >       git reflog exists refs/heads/e &&\n> > -     echo Hello >expect &&\n> > -     git config branch.e.dummy >actual &&\n> > -     test_cmp expect actual &&\n> > -     echo Hello >expect &&\n> > -     git config branch.d.dummy >actual &&\n> > -     test_cmp expect actual\n> > +     test_cmp_config Hello branch.e.dummy &&\n> > +     test_cmp_config Hello branch.d.dummy\n> >  '\n>\n> This test used to leave both branch.d.dummy and branch.e.dummy behind\n> for later tests.  Now with this patch, we clean branch.d.dummy\n> because we use test_config, but branch.e.dummy that was copied by\n> successful \"git branch -c\" will still be left.\n>\n>  - It is unforunate that it is impossible to verify that the change\n>    in behaviour for branch.d.dummy is correct.  Without checking all\n>    the remainder of the test (and no, grepping for branch.d.dummy is\n>    not \"checking all the remainder\"---a later \"branch -c d x\" would\n>    have created brnach.x.dummy in the original, but with this patch,\n>    it would not), which is time consuming, that is.\n>\n>    I trust you made sure that branch.d.dummy is never used after\n>    this test is done---it would have been good to explain it either\n>    in the proposed log message or after three-dash that you did\n>    check and how to save reviewer bandwidth.\n\nI will add a comment, and will (first) more diligently check for\ndependencies on things now-removed.\n\nMy strategy was, frankly, a little more haphazard: eyeball the intent,\nlook for references in the following couple tests, and otherwise\nassume that if the tests still pass, it means they didn't unexpectedly\ndepend on this.\n\nFwiw, the not-trivial-but-still-straightforward approach I'm using is\nto search case-sensitively for the word \"d\" in this example. a, b, c\nand d are all bad because they are common english words or flags used\nthroughout this test, but other letters and combinations are easier to\ncheck in this reasonably-simple way.\n\n>\n>  - Are you deliberatly leaving branch.e.dummy uncleaned, or is it a\n>    mere oversight?\n>\n\nSomewhere in-between. My intent with these changes was to use the\nright helpers/patterns, but I did not aspire to making sure nothing\nleaks between tests at all.\n\nGenerally speaking, none of the tests I've seen (in this file or\nothers) clean up / delete the *branches* they create - presumably\nbecause there's no significant need - the existence of branches rarely\nor never has side-effects unless explicitly referenced. Config, on the\nother hand, is a good thing to clean up by default, because it is much\nmore likely to interfere with later tests.\n\nSomething like configuring \"branch.x.dummy\" (or the more meaningful\n\"branch.x.merge\") straddles those 2 worlds - I would use test_config\nto be consistent if setting one manually, but it's still\nbranch-specific stuff so I wouldn't be diligent about removing it if\nit was created as a side-effect of another command like \"git branch\n-c\" - just like I'm not removing the new branch itself.\n\nThat said, now that you've called my attention to it, I'll look for\nleaky branch configs :)\n\nI will also add a note clarifying \"intend to use the right\npatterns/helpers, but not necessarily to eliminate state leaks between\ntests\" in the commit message.\n\n> >  test_expect_success 'git branch --copy is a synonym for -c' '\n> >       git branch --create-reflog copy &&\n> >       git reflog exists refs/heads/copy &&\n> > -     git config branch.copy.dummy Hello &&\n> > +     test_config branch.copy.dummy Hello &&\n> >       git branch --copy copy copy-to &&\n> >       git reflog exists refs/heads/copy &&\n> >       git reflog exists refs/heads/copy-to &&\n> > -     echo Hello >expect &&\n> > -     git config branch.copy.dummy >actual &&\n> > -     test_cmp expect actual &&\n> > -     echo Hello >expect &&\n> > -     git config branch.copy-to.dummy >actual &&\n> > -     test_cmp expect actual\n> > +     test_cmp_config Hello branch.copy.dummy &&\n> > +     test_cmp_config Hello branch.copy-to.dummy\n> >  '\n>\n> The same comment for branch.copy.dummy and branch.copy-to.dummy\n> applies.\n>\n> I'll stop here for now.  Thanks for starting this clean-up.\n\nThank you!\n"}]}