{"thread":{"id":"65549","subject":"[PATCH 1/8] test-lib: allow bare repository access when breaking changes are enabled","startedAt":"2026-04-24T15:01:23Z","lastAt":"2026-04-26T14:38:53Z","messageCount":19,"participants":["Johannes Schindelin via GitGitGadget","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"542250","messageId":"62707b410977af2c80d98306455aaec55499f606.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 1/8] test-lib: allow bare repository access when breaking changes are enabled","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:10Z","receivedAt":"2026-04-24T15:01:23Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nA future patch will change the `safe.bareRepository` default from\n`all` to `explicit` under `WITH_BREAKING_CHANGES`. At that point,\nevery test that operates on a bare repository through implicit\ndiscovery would fail, regardless of whether the test is actually\nabout discovery or about how a specific command behaves once inside\na bare repository.\n\nThe maintainer suggested [1] setting `safe.bareRepository=all` in\nthe test environment's global config whenever `WITH_BREAKING_CHANGES`\nis in effect, rather than adjusting each affected test to access\nbare repositories explicitly (via `--git-dir`, `GIT_DIR`, or\nsimilar). This means the test suite continues to exercise only the\nhistorical default behavior even after the user-facing default\nchanges, relying on a small number of dedicated tests in t0035 to\nvalidate the new, stricter default.\n\nSince `$HOME` points at the trash directory (which doubles as the\ntest repository's working tree), writing to `$HOME/.gitconfig` also\ncreates a file inside the working tree. Exclude it via\n`.git/info/exclude` to limit the fallout, though this does not\nhelp tests that use `git ls-files --others` without\n`--exclude-standard` or `git status --ignored`; those are addressed\nby subsequent commits.\n\n[1] https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/\n\nOriginal-patch-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/test-lib.sh | 6 ++++++\n 1 file changed, 6 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 70fd3e9baf..b8726f4647 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1597,6 +1597,12 @@ cd -P \"$TRASH_DIRECTORY\" || BAIL_OUT \"cannot cd -P to \\\"$TRASH_DIRECTORY\\\"\"\n TRASH_DIRECTORY=$(pwd)\n HOME=\"$TRASH_DIRECTORY\"\n \n+if test -n \"$WITH_BREAKING_CHANGES\"\n+then\n+\tgit config --global safe.bareRepository all &&\n+\techo \"/.gitconfig\" >>.git/info/exclude\n+fi\n+\n start_test_output \"$0\"\n \n # Convenience\n-- \ngitgitgadget\n\n"},{"id":"542251","messageId":"d9a2e76f3c2a96523f1655ef2f73f9b03ce88af3.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 2/8] t7900: do not let `$HOME/.gitconfig` interfere with XDG tests","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:11Z","receivedAt":"2026-04-24T15:01:23Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe XDG config tests for `git maintenance register/unregister`\ncreate a fresh `$XDG_CONFIG_HOME/git/config` and expect git to use\nthat location. However, if `$HOME/.gitconfig` exists (which may\nhappen when test-lib.sh writes global config, e.g. to set\n`safe.bareRepository`), git prefers `$HOME/.gitconfig` over the XDG\nlocation, and the `maintenance.repo` entry ends up in the wrong\nfile.\n\nThis is an inherent consequence of setting global config in\ntest-lib.sh rather than adjusting individual tests: writing any\nentry to `$HOME/.gitconfig` has side effects beyond the intended\nsetting, because the mere existence of that file changes which\nglobal config location git prefers for all subsequent writes.\nIndividual per-test adjustments would not have this interaction.\n\nFix this by overriding `HOME` to a non-existent directory inside the\nsubshells that test XDG behavior. Since these subshells already\noverride `XDG_CONFIG_HOME`, they do not need `$HOME/.gitconfig` at\nall, and the subshell scoping ensures the original `HOME` is\nrestored automatically.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7900-maintenance.sh | 12 ++++++++++--\n 1 file changed, 10 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh\nindex 4700beacc1..4358df0424 100755\n--- a/t/t7900-maintenance.sh\n+++ b/t/t7900-maintenance.sh\n@@ -101,8 +101,12 @@ test_expect_success \"maintenance.autoDetach overrides gc.autoDetach\" '\n test_expect_success 'register uses XDG_CONFIG_HOME config if it exists' '\n \ttest_when_finished rm -r .config/git/config &&\n \t(\n+\t\t# Override HOME so that .gitconfig (which test-lib.sh may\n+\t\t# have created, e.g. to set safe.bareRepository) does not\n+\t\t# take precedence over the XDG location.\n+\t\tHOME=$PWD/must-not-exist &&\n \t\tXDG_CONFIG_HOME=.config &&\n-\t\texport XDG_CONFIG_HOME &&\n+\t\texport HOME XDG_CONFIG_HOME &&\n \t\tmkdir -p $XDG_CONFIG_HOME/git &&\n \t\t>$XDG_CONFIG_HOME/git/config &&\n \t\tgit maintenance register &&\n@@ -124,8 +128,12 @@ test_expect_success 'register does not need XDG_CONFIG_HOME config to exist' '\n test_expect_success 'unregister uses XDG_CONFIG_HOME config if it exists' '\n \ttest_when_finished rm -r .config/git/config &&\n \t(\n+\t\t# Override HOME so that .gitconfig (which test-lib.sh may\n+\t\t# have created, e.g. to set safe.bareRepository) does not\n+\t\t# take precedence over the XDG location.\n+\t\tHOME=$PWD/must-not-exist &&\n \t\tXDG_CONFIG_HOME=.config &&\n-\t\texport XDG_CONFIG_HOME &&\n+\t\texport HOME XDG_CONFIG_HOME &&\n \t\tmkdir -p $XDG_CONFIG_HOME/git &&\n \t\t>$XDG_CONFIG_HOME/git/config &&\n \t\tgit maintenance register &&\n-- \ngitgitgadget\n\n"},{"id":"542252","messageId":"9c10e72eedc76e03306664b5c979e536a50356e2.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 3/8] t1300: remove global config settings injected by test-lib.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:12Z","receivedAt":"2026-04-24T15:01:24Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nSince test-lib.sh now writes `safe.bareRepository=all` to the global\nconfig when `WITH_BREAKING_CHANGES` is in effect, that entry shows\nup in `git config --list` output. Tests in t1300 that expect exact\nconfig contents then fail because of this unexpected extra line.\n\nUnlike the working-tree contamination fixed in the preceding\ncommits, this is not about the file's existence but about its\ncontent leaking into test expectations. Since t1300 does not use\nbare repositories, simply remove the injected setting in a\npreparatory step.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nAssisted-by: Claude Opus 4.6\n---\n t/t1300-config.sh | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/t/t1300-config.sh b/t/t1300-config.sh\nindex 128971ee12..11fc976f3a 100755\n--- a/t/t1300-config.sh\n+++ b/t/t1300-config.sh\n@@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+# test-lib.sh may have added global config (e.g. safe.bareRepository)\n+# that would appear in \"git config --list\" output and break tests\n+# that expect exact config contents.\n+test_expect_success 'remove global config from test-lib.sh' '\n+\ttest_might_fail git config --global --unset-all safe.bareRepository\n+'\n+\n for mode in legacy subcommands\n do\n \n-- \ngitgitgadget\n\n"},{"id":"542253","messageId":"ef57244778d8f72754801d80a9e7e8ad034cec28.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 6/8] ls-files tests: filter `.gitconfig` from `--others` output","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:15Z","receivedAt":"2026-04-24T15:01:28Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe global `safe.bareRepository=all` setting in test-lib.sh is\nwritten to `$HOME/.gitconfig`, which unfortunately lives inside the\ntest repository's working tree. The `.git/info/exclude` entry added\nalongside it handles most commands, but `git ls-files --others`\nwithout `--exclude-standard` does not consult `info/exclude` at\nall, so the file appears in the output.\n\nIdeally, each test that accesses a bare repository would simply\nspecify `--git-dir` or `GIT_DIR` explicitly, which would require no\nglobal config and produce no side effects in the working tree. As\nthat approach was not taken, filter `.gitconfig` from the output\nbefore comparing against expected results. In t7104, the test\nalready uses `--exclude-standard`, so it suffices to switch from\nthe bare `git ls-files -o` to `git ls-files -o --exclude-standard`\nwhich respects the `info/exclude` entry; the other tests\ndeliberately omit `--exclude-standard` because their purpose is to\nverify unfiltered `--others` output.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t3000-ls-files-others.sh                         | 4 ++++\n t/t3001-ls-files-others-exclude.sh                 | 3 +++\n t/t3002-ls-files-dashpath.sh                       | 2 ++\n t/t3009-ls-files-others-nonsubmodule.sh            | 1 +\n t/t3011-common-prefixes-and-directory-traversal.sh | 3 ++-\n t/t7104-reset-hard.sh                              | 2 +-\n t/test-lib-functions.sh                            | 8 ++++++++\n 7 files changed, 21 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh\nindex b41e7f0daa..b4f0fbfc55 100755\n--- a/t/t3000-ls-files-others.sh\n+++ b/t/t3000-ls-files-others.sh\n@@ -53,16 +53,19 @@ test_expect_success 'setup: expected output' '\n \n test_expect_success 'ls-files --others' '\n \tgit ls-files --others >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected1 output\n '\n \n test_expect_success 'ls-files --others --directory' '\n \tgit ls-files --others --directory >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected2 output\n '\n \n test_expect_success '--no-empty-directory hides empty directory' '\n \tgit ls-files --others --directory --no-empty-directory >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected3 output\n '\n \n@@ -70,6 +73,7 @@ test_expect_success 'ls-files --others handles non-submodule .git' '\n \tmkdir not-a-submodule &&\n \techo foo >not-a-submodule/.git &&\n \tgit ls-files -o >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected1 output\n '\n \ndiff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh\nindex 4b67646285..202fb8d9ea 100755\n--- a/t/t3001-ls-files-others-exclude.sh\n+++ b/t/t3001-ls-files-others-exclude.sh\n@@ -72,6 +72,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -84,6 +85,7 @@ test_expect_success 'git ls-files --others with \\r\\n line endings.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -99,6 +101,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \ndiff --git a/t/t3002-ls-files-dashpath.sh b/t/t3002-ls-files-dashpath.sh\nindex 31462cb441..6acaadbd67 100755\n--- a/t/t3002-ls-files-dashpath.sh\n+++ b/t/t3002-ls-files-dashpath.sh\n@@ -24,6 +24,7 @@ test_expect_success 'setup' '\n test_expect_success 'git ls-files without path restriction.' '\n \ttest_when_finished \"rm -f expect\" &&\n \tgit ls-files --others >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-\\EOF &&\n \t--\n \t-foo\n@@ -63,6 +64,7 @@ test_expect_success 'git ls-files with path restriction with -- --.' '\n test_expect_success 'git ls-files with no path restriction.' '\n \ttest_when_finished \"rm -f expect\" &&\n \tgit ls-files --others -- >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-\\EOF &&\n \t--\n \t-foo\ndiff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh\nindex 963f3462b7..dc990c277b 100755\n--- a/t/t3009-ls-files-others-nonsubmodule.sh\n+++ b/t/t3009-ls-files-others-nonsubmodule.sh\n@@ -36,6 +36,7 @@ test_expect_success 'setup: directories' '\n \n test_expect_success 'ls-files --others handles untracked git repositories' '\n \tgit ls-files -o >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-EOF &&\n \tnonrepo-untracked-file/untracked\n \toutput\ndiff --git a/t/t3011-common-prefixes-and-directory-traversal.sh b/t/t3011-common-prefixes-and-directory-traversal.sh\nindex 3da5b2b6e7..455e97954d 100755\n--- a/t/t3011-common-prefixes-and-directory-traversal.sh\n+++ b/t/t3011-common-prefixes-and-directory-traversal.sh\n@@ -26,7 +26,7 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'git ls-files -o shows the right entries' '\n-\tcat <<-EOF >expect &&\n+\tcat >expect <<-EOF &&\n \t.gitignore\n \tactual\n \tan_ignored_dir/ignored\n@@ -39,6 +39,7 @@ test_expect_success 'git ls-files -o shows the right entries' '\n \tuntracked_repo/\n \tEOF\n \tgit ls-files -o >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t7104-reset-hard.sh b/t/t7104-reset-hard.sh\nindex 7948ec392b..c23d6e3f52 100755\n--- a/t/t7104-reset-hard.sh\n+++ b/t/t7104-reset-hard.sh\n@@ -21,7 +21,7 @@ test_expect_success setup '\n \trm -f hello &&\n \tmkdir -p hello &&\n \t>hello/world &&\n-\ttest \"$(git ls-files -o)\" = hello/world\n+\ttest \"$(git ls-files -o --exclude-standard)\" = hello/world\n \n '\n \ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex f3af10fb7e..0505da78e8 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -2069,3 +2069,11 @@ test_trailing_hash () {\n test_redact_non_printables () {\n     tr -d \"\\n\\r\" | tr \"[\\001-\\040][\\177-\\377]\" \".\"\n }\n+\n+# Remove .gitconfig entries from a file in place.  test-lib.sh may\n+# create $HOME/.gitconfig (e.g. to set safe.bareRepository) which\n+# can appear in ls-files or status output.\n+test_filter_gitconfig () {\n+\tsed \"/\\\\.gitconfig/d\" \"$1\" >\"$1.filtered\" &&\n+\tmv \"$1.filtered\" \"$1\"\n+}\n-- \ngitgitgadget\n\n"},{"id":"542254","messageId":"56fe902644452f98b39d2ee4217228416705f14c.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 7/8] status tests: filter `.gitconfig` from status output","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:16Z","receivedAt":"2026-04-24T15:01:30Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nSince test-lib.sh creates `$HOME/.gitconfig` when\n`WITH_BREAKING_CHANGES` is in effect, the file appears in `git\nstatus` output as either untracked (`?? .gitconfig`) or ignored\n(`!! .gitconfig` / `! .gitconfig`, depending on porcelain version),\nbecause the `.git/info/exclude` entry causes git to treat it as an\nignored file rather than hiding it entirely.\n\nIn t7061 and t7521, which are pervasively affected, introduce a\n`filter_gitconfig` helper that strips all status-prefix variants of\n`.gitconfig` from the output before comparison. In the remaining\nscripts (t7060, t7064, t7508), apply targeted adjustments.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7060-wtstatus.sh        |  3 +--\n t/t7061-wtstatus-ignore.sh | 27 +++++++++++++++++++++++++++\n t/t7064-wtstatus-pv2.sh    |  1 +\n t/t7508-status.sh          |  4 ++++\n t/t7521-ignored-mode.sh    |  1 +\n 5 files changed, 34 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh\nindex 0f4344c55e..942ddbbf0e 100755\n--- a/t/t7060-wtstatus.sh\n+++ b/t/t7060-wtstatus.sh\n@@ -9,6 +9,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n test_expect_success setup '\n \tgit config --global advice.statusuoption false &&\n+\techo \"/.gitconfig\" >>.git/info/exclude &&\n \ttest_commit A &&\n \ttest_commit B oneside added &&\n \tgit checkout A^0 &&\n@@ -221,7 +222,6 @@ test_expect_success 'status --branch with detached HEAD' '\n \tgit status --branch --porcelain >actual &&\n \tcat >expected <<-EOF &&\n \t## HEAD (no branch)\n-\t?? .gitconfig\n \t?? actual\n \t?? expect\n \t?? expected\n@@ -237,7 +237,6 @@ test_expect_success 'status --porcelain=v1 --branch with detached HEAD' '\n \tgit status --branch --porcelain=v1 >actual &&\n \tcat >expected <<-EOF &&\n \t## HEAD (no branch)\n-\t?? .gitconfig\n \t?? actual\n \t?? expect\n \t?? expected\ndiff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh\nindex 2f9bea9793..14ddaba2f3 100755\n--- a/t/t7061-wtstatus-ignore.sh\n+++ b/t/t7061-wtstatus-ignore.sh\n@@ -18,6 +18,7 @@ test_expect_success 'status untracked directory with --ignored' '\n \t: >untracked/ignored &&\n \t: >untracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -27,6 +28,7 @@ test_expect_success 'same with gitignore starting with BOM' '\n \t: >untracked/ignored &&\n \t: >untracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -40,18 +42,22 @@ test_expect_success 'status untracked files --ignored with pathspec (no match)'\n test_expect_success 'status untracked files --ignored with pathspec (literal match)' '\n \tgit status --porcelain --ignored -- untracked/ignored >actual &&\n \techo \"!! untracked/ignored\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \tgit status --porcelain --ignored -- untracked/uncommitted >actual &&\n \techo \"?? untracked/uncommitted\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n test_expect_success 'status untracked files --ignored with pathspec (glob match)' '\n \tgit status --porcelain --ignored -- untracked/i\\* >actual &&\n \techo \"!! untracked/ignored\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \tgit status --porcelain --ignored -- untracked/u\\* >actual &&\n \techo \"?? untracked/uncommitted\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -65,6 +71,7 @@ EOF\n \n test_expect_success 'status untracked directory with --ignored -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n cat >expected <<\\EOF\n@@ -76,9 +83,11 @@ test_expect_success 'status of untracked directory with --ignored works with or\n \tgit status --porcelain --ignored >tmp &&\n \tgrep untracked/ tmp >actual &&\n \trm tmp &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \n \tgit status --porcelain --ignored untracked/ >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -89,6 +98,7 @@ EOF\n \n test_expect_success 'status prefixed untracked sub-directory with --ignored -u' '\n \tgit status --porcelain --ignored -u untracked/ >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -104,6 +114,7 @@ test_expect_success 'status ignored directory with --ignore' '\n \tmkdir ignored &&\n \t: >ignored/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -116,6 +127,7 @@ EOF\n \n test_expect_success 'status ignored directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -130,6 +142,7 @@ test_expect_success 'status empty untracked directory with --ignore' '\n \tmkdir untracked-ignored &&\n \tmkdir untracked-ignored/test &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -141,6 +154,7 @@ EOF\n \n test_expect_success 'status empty untracked directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -155,6 +169,7 @@ test_expect_success 'status untracked directory with ignored files with --ignore\n \t: >untracked-ignored/ignored &&\n \t: >untracked-ignored/test/ignored &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -168,6 +183,7 @@ EOF\n \n test_expect_success 'status untracked directory with ignored files with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -185,6 +201,7 @@ test_expect_success 'status ignored tracked directory with --ignore' '\n \tgit commit -m. &&\n \techo \"tracked\" >.gitignore &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -196,6 +213,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -208,6 +226,7 @@ EOF\n test_expect_success 'status ignored tracked directory and ignored file with --ignore' '\n \techo \"committed\" >>.gitignore &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -219,6 +238,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory and ignored file with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -233,6 +253,7 @@ test_expect_success 'status ignored tracked directory and uncommitted file with\n \techo \"tracked\" >.gitignore &&\n \t: >tracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -245,6 +266,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory and uncommitted file with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -260,6 +282,7 @@ test_expect_success 'status ignored tracked directory with uncommitted file in u\n \tmkdir tracked/ignored &&\n \t: >tracked/ignored/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -272,6 +295,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -287,6 +311,7 @@ test_expect_success 'status ignored tracked directory with uncommitted file in t\n \tgit add -f tracked/ignored/committed &&\n \tgit commit -m. &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -299,6 +324,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -310,6 +336,7 @@ test_expect_success 'status ignores submodule in excluded directory' '\n \tgit init tracked/submodule &&\n \ttest_commit -C tracked/submodule initial &&\n \tgit status --porcelain --ignored -u tracked/submodule >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \ndiff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh\nindex 8bbc5ce6d9..be6c931a96 100755\n--- a/t/t7064-wtstatus-pv2.sh\n+++ b/t/t7064-wtstatus-pv2.sh\n@@ -231,6 +231,7 @@ test_expect_success 'ignored files are printed with --ignored' '\n \tEOF\n \n \tgit status --porcelain=v2 --ignored --untracked-files=all >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex a5e21bf8bf..5f76ec62d8 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -263,6 +263,7 @@ test_expect_success 'status with gitignore' '\n \t!! untracked\n \tEOF\n \tgit status -s --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output &&\n \n \tcat >expect <<\\EOF &&\n@@ -296,6 +297,7 @@ Ignored files:\n \n EOF\n \tgit status --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -328,6 +330,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '\n \t!! untracked\n \tEOF\n \tgit status -s --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output &&\n \n \tcat >expect <<\\EOF &&\n@@ -358,6 +361,7 @@ Ignored files:\n \n EOF\n \tgit status --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \ndiff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh\nindex a88b02b06e..7ea0b0d2f2 100755\n--- a/t/t7521-ignored-mode.sh\n+++ b/t/t7521-ignored-mode.sh\n@@ -30,6 +30,7 @@ test_expect_success 'Verify behavior of status on directories with ignored files\n \t\tdir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&\n \n \tgit status --porcelain=v2 --ignored=matching --untracked-files=all >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n-- \ngitgitgadget\n\n"},{"id":"542255","messageId":"64db45e38575015b6e0ffdeff39d9ba851eb1e38.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 8/8] safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:17Z","receivedAt":"2026-04-24T15:01:31Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen an attacker can convince a user to clone a crafted repository\nthat contains an embedded bare repository with malicious hooks, any Git\ncommand the user runs after entering that subdirectory will discover\nthe bare repository and execute the hooks. The user does not even need\nto run a Git command explicitly: many shell prompts run `git status`\nin the background to display branch and dirty state information, and\n`git status` in turn may invoke the fsmonitor hook if so configured,\nmaking the user vulnerable the moment they `cd` into the directory. The\n`safe.bareRepository` configuration variable (introduced in 8959555cee7e\n(setup_git_directory(): add an owner check for the top-level directory,\n2022-03-02)) already provides protection against this attack vector by\nallowing users to set it to \"explicit\", but the default remained \"all\"\nfor backwards compatibility.\n\nSince Git 3.0 is the natural point to change defaults to safer\nvalues, flip the default from \"all\" to \"explicit\" when built with\n`WITH_BREAKING_CHANGES`. This means Git will refuse to work with bare\nrepositories that are discovered implicitly by walking up the directory\ntree. Bare repositories specified via `--git-dir` or `GIT_DIR` continue\nto work, and directories that look like `.git`, worktrees, or submodule\ndirectories are unaffected (the existing `is_implicit_bare_repo()`\nwhitelist handles those cases).\n\nUsers who rely on implicit bare repository discovery can restore the\nprevious behavior by setting `safe.bareRepository=all` in their global\nor system configuration.\n\nThe test for the \"safe.bareRepository in the repository\" scenario\nneeded a more involved fix: it writes a `safe.bareRepository=all`\nentry into the bare repository's own config to verify that repo-local\nconfig does not override the protected (global) setting. Previously,\n`test_config -C` was used to write that entry, but its cleanup runs `git\n-C <bare-repo> config --unset`, which itself fails when the default is\n\"explicit\" and the global config has already been cleaned up. Switching\nto direct git config --file access avoids going through repository\ndiscovery entirely.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/BreakingChanges.adoc | 24 ++++++++++++++++++++++++\n Documentation/config/safe.adoc     | 10 ++++++++--\n setup.c                            |  4 ++++\n t/t0035-safe-bare-repository.sh    | 10 ++++++++--\n 4 files changed, 44 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc\nindex af59c43f42..73bb939359 100644\n--- a/Documentation/BreakingChanges.adoc\n+++ b/Documentation/BreakingChanges.adoc\n@@ -216,6 +216,30 @@ would be significant, we may decide to defer this change to a subsequent minor\n release. This evaluation will also take into account our own experience with\n how painful it is to keep Rust an optional component.\n \n+* The default value of `safe.bareRepository` will change from `all` to\n+  `explicit`. It is all too easy for an attacker to trick a user into cloning a\n+  repository that contains an embedded bare repository with malicious hooks\n+  configured. If the user enters that subdirectory and runs any Git command, Git\n+  discovers the bare repository and the hooks fire. The user does not even need\n+  to run a Git command explicitly: many shell prompts run `git status` in the\n+  background to display branch and dirty state information, and `git status` in\n+  turn may invoke the fsmonitor hook if so configured, making the user\n+  vulnerable the moment they `cd` into the directory. The `safe.bareRepository`\n+  configuration variable was introduced in 8959555cee (setup_git_directory():\n+  add an owner check for the top-level directory, 2022-03-02) with a default of\n+  `all` to preserve backwards compatibility.\n++\n+Changing the default to `explicit` means that Git will refuse to work with bare\n+repositories that are discovered implicitly by walking up the directory tree.\n+Bare repositories specified explicitly via the `--git-dir` command-line option\n+or the `GIT_DIR` environment variable continue to work regardless of this\n+setting. Repositories that look like a `.git` directory, a worktree, or a\n+submodule directory are also unaffected.\n++\n+Users who rely on implicit discovery of bare repositories can restore the\n+previous behavior by setting `safe.bareRepository=all` in their global or\n+system configuration.\n+\n === Removals\n \n * Support for grafting commits has long been superseded by git-replace(1).\ndiff --git a/Documentation/config/safe.adoc b/Documentation/config/safe.adoc\nindex 2d45c98b12..5b1690aebe 100644\n--- a/Documentation/config/safe.adoc\n+++ b/Documentation/config/safe.adoc\n@@ -2,10 +2,12 @@ safe.bareRepository::\n \tSpecifies which bare repositories Git will work with. The currently\n \tsupported values are:\n +\n-* `all`: Git works with all bare repositories. This is the default.\n+* `all`: Git works with all bare repositories. This is the default in\n+  Git 2.x.\n * `explicit`: Git only works with bare repositories specified via\n   the top-level `--git-dir` command-line option, or the `GIT_DIR`\n-  environment variable (see linkgit:git[1]).\n+  environment variable (see linkgit:git[1]). This will be the default\n+  in Git 3.0.\n +\n If you do not use bare repositories in your workflow, then it may be\n beneficial to set `safe.bareRepository` to `explicit` in your global\n@@ -13,6 +15,10 @@ config. This will protect you from attacks that involve cloning a\n repository that contains a bare repository and running a Git command\n within that directory.\n +\n+If you use bare repositories regularly and want to preserve the current\n+behavior after upgrading to Git 3.0, set `safe.bareRepository` to `all`\n+in your global or system config.\n++\n This config setting is only respected in protected configuration (see\n <<SCOPES>>). This prevents untrusted repositories from tampering with\n this value.\ndiff --git a/setup.c b/setup.c\nindex 7ec4427368..17c0662076 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1485,7 +1485,11 @@ static int allowed_bare_repo_cb(const char *key, const char *value,\n \n static enum allowed_bare_repo get_allowed_bare_repo(void)\n {\n+#ifdef WITH_BREAKING_CHANGES\n+\tenum allowed_bare_repo result = ALLOWED_BARE_REPO_EXPLICIT;\n+#else\n \tenum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;\n+#endif\n \tgit_protected_config(allowed_bare_repo_cb, &result);\n \treturn result;\n }\ndiff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh\nindex ae7ef092ab..1d3d19f5b4 100755\n--- a/t/t0035-safe-bare-repository.sh\n+++ b/t/t0035-safe-bare-repository.sh\n@@ -44,11 +44,16 @@ test_expect_success 'setup an embedded bare repo, secondary worktree and submodu\n \ttest_path_is_dir outer-repo/.git/modules/subn\n '\n \n-test_expect_success 'safe.bareRepository unset' '\n+test_expect_success !WITH_BREAKING_CHANGES 'safe.bareRepository unset' '\n \ttest_unconfig --global safe.bareRepository &&\n \texpect_accepted_implicit -C outer-repo/bare-repo\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'safe.bareRepository unset (defaults to explicit)' '\n+\ttest_unconfig --global safe.bareRepository &&\n+\texpect_rejected -C outer-repo/bare-repo\n+'\n+\n test_expect_success 'safe.bareRepository=all' '\n \ttest_config_global safe.bareRepository all &&\n \texpect_accepted_implicit -C outer-repo/bare-repo\n@@ -63,7 +68,8 @@ test_expect_success 'safe.bareRepository in the repository' '\n \t# safe.bareRepository must not be \"explicit\", otherwise\n \t# git config fails with \"fatal: not in a git directory\" (like\n \t# safe.directory)\n-\ttest_config -C outer-repo/bare-repo safe.bareRepository all &&\n+\ttest_when_finished \"git config --file outer-repo/bare-repo/config --unset safe.bareRepository\" &&\n+\tgit config --file outer-repo/bare-repo/config safe.bareRepository all &&\n \ttest_config_global safe.bareRepository explicit &&\n \texpect_rejected -C outer-repo/bare-repo\n '\n-- \ngitgitgadget\n"},{"id":"542256","messageId":"092ec11621ce698e3f3af7bd5024d338440ffce7.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 4/8] t1305: use `--git-dir=.` for bare repo in include cycle test","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:13Z","receivedAt":"2026-04-24T15:01:58Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEarlier tests in t1305 overwrite `$HOME/.gitconfig` with their own\ncontent as part of testing config includes. This clobbers the\n`safe.bareRepository=all` entry that test-lib.sh writes when\n`WITH_BREAKING_CHANGES` is in effect, causing `git -C cycle config`\nto fail with \"not in a git directory\" when it tries to access the\nbare repository created by `git init --bare cycle`.\n\nUse `--git-dir=.` to access the bare repo explicitly, avoiding the\ndependency on global config for repository discovery.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1305-config-include.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 6e51f892f3..f3892578e4 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -350,9 +350,9 @@ test_expect_success 'conditional include, onbranch, implicit /** for /' '\n \n test_expect_success 'include cycles are detected' '\n \tgit init --bare cycle &&\n-\tgit -C cycle config include.path cycle &&\n+\tgit -C cycle --git-dir=. config include.path cycle &&\n \tgit config -f cycle/cycle include.path config &&\n-\ttest_must_fail git -C cycle config --get-all test.value 2>stderr &&\n+\ttest_must_fail git -C cycle --git-dir=. config --get-all test.value 2>stderr &&\n \tgrep \"exceeded maximum include depth\" stderr\n '\n \n-- \ngitgitgadget\n\n"},{"id":"542257","messageId":"3aca302275225d374d33789f56efae47c025bb32.1777042877.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH 5/8] t5601: restore `.gitconfig` after includeIf test","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:14Z","receivedAt":"2026-04-24T15:01:58Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOne test in t5601 overwrites `$HOME/.gitconfig` with an `includeIf`\nconfiguration snippet and removes the file in its cleanup. This\ndestroys the `safe.bareRepository=all` entry that test-lib.sh\nwrites when `WITH_BREAKING_CHANGES` is in effect, causing later\ntests that use `git -C <bare-repo> config` to fail with \"not in a\ngit directory\".\n\nBack up `.gitconfig` before overwriting and restore it in the\ncleanup, so the global config survives into subsequent tests.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t5601-clone.sh | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d743d986c4..3dd229c186 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -813,7 +813,9 @@ test_expect_success 'clone with includeIf' '\n \ttest_when_finished \"rm -rf repo \\\"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\\\"\" &&\n \tgit clone --bare --no-local src \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n \n-\ttest_when_finished \"rm \\\"$HOME\\\"/.gitconfig\" &&\n+\ttest_when_finished \"cp \\\"$HOME\\\"/.gitconfig.bak \\\n+\t\t\\\"$HOME\\\"/.gitconfig 2>/dev/null || rm -f \\\"$HOME\\\"/.gitconfig\" &&\n+\tcp \"$HOME\"/.gitconfig \"$HOME\"/.gitconfig.bak 2>/dev/null &&\n \tcat >\"$HOME\"/.gitconfig <<-EOF &&\n \t[includeIf \"onbranch:something\"]\n \t\tpath = /does/not/exist.inc\n-- \ngitgitgadget\n\n"},{"id":"542258","messageId":"pull.2098.git.1777042877.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":null,"subject":"[PATCH 0/8] safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-24T15:01:09Z","receivedAt":"2026-04-24T15:02:26Z","isPatch":true,"body":"This supersedes my earlier series [*1*] which took the approach of adjusting\nindividual tests to access bare repositories explicitly.\n\nAs Junio suggested [*2*], this series instead takes the approach of setting\nsafe.bareRepository=all in the test environment's global config whenever\nWITH_BREAKING_CHANGES is in effect, so that existing tests continue to work\nwithout individual modifications.\n\nImplementing this turned out to require a number of follow-up adjustments,\nbecause writing to $HOME/.gitconfig has side effects beyond the intended\nsetting: $HOME is the trash directory, which doubles as the test\nrepository's working tree, so the file shows up in ls-files and status\noutput, and tests that manipulate $HOME/.gitconfig for their own purposes\ncan clobber or remove the setting. Patches 2 through 7 address these\ninteractions in the affected test scripts.\n\nThe final patch flips the safe.bareRepository default to \"explicit\" under\nWITH_BREAKING_CHANGES.\n\nFootnote [*1*]:\nhttps://lore.kernel.org/git/pull.2076.git.1775140403.gitgitgadget@gmail.com/\n\nFootnote [*2*]: https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/\n\nJohannes Schindelin (8):\n  test-lib: allow bare repository access when breaking changes are\n    enabled\n  t7900: do not let `$HOME/.gitconfig` interfere with XDG tests\n  t1300: remove global config settings injected by test-lib.sh\n  t1305: use `--git-dir=.` for bare repo in include cycle test\n  t5601: restore `.gitconfig` after includeIf test\n  ls-files tests: filter `.gitconfig` from `--others` output\n  status tests: filter `.gitconfig` from status output\n  safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES\n\n Documentation/BreakingChanges.adoc            | 24 +++++++++++++++++\n Documentation/config/safe.adoc                | 10 +++++--\n setup.c                                       |  4 +++\n t/t0035-safe-bare-repository.sh               | 10 +++++--\n t/t1300-config.sh                             |  7 +++++\n t/t1305-config-include.sh                     |  4 +--\n t/t3000-ls-files-others.sh                    |  4 +++\n t/t3001-ls-files-others-exclude.sh            |  3 +++\n t/t3002-ls-files-dashpath.sh                  |  2 ++\n t/t3009-ls-files-others-nonsubmodule.sh       |  1 +\n ...common-prefixes-and-directory-traversal.sh |  3 ++-\n t/t5601-clone.sh                              |  4 ++-\n t/t7060-wtstatus.sh                           |  3 +--\n t/t7061-wtstatus-ignore.sh                    | 27 +++++++++++++++++++\n t/t7064-wtstatus-pv2.sh                       |  1 +\n t/t7104-reset-hard.sh                         |  2 +-\n t/t7508-status.sh                             |  4 +++\n t/t7521-ignored-mode.sh                       |  1 +\n t/t7900-maintenance.sh                        | 12 +++++++--\n t/test-lib-functions.sh                       |  8 ++++++\n t/test-lib.sh                                 |  6 +++++\n 21 files changed, 127 insertions(+), 13 deletions(-)\n\n\nbase-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2098%2Fdscho%2Fsafe-bare-repo-default-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2098/dscho/safe-bare-repo-default-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2098\n-- \ngitgitgadget\n"},{"id":"542314","messageId":"xmqqldea7dpg.fsf@gitster.g","threadId":"65549","inReplyTo":"ef57244778d8f72754801d80a9e7e8ad034cec28.1777042877.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 6/8] ls-files tests: filter `.gitconfig` from `--others` output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-04-26T00:44:11Z","receivedAt":"2026-04-26T00:44:14Z","isPatch":true,"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> +# Remove .gitconfig entries from a file in place.  test-lib.sh may\n> +# create $HOME/.gitconfig (e.g. to set safe.bareRepository) which\n> +# can appear in ls-files or status output.\n> +test_filter_gitconfig () {\n> +\tsed \"/\\\\.gitconfig/d\" \"$1\" >\"$1.filtered\" &&\n> +\tmv \"$1.filtered\" \"$1\"\n> +}\n\nThanks.\n\nWhen I suggested the \"just use the usual configuration mechanism to\nkeep the semantics of existing bare repository tests, and that would\nbe very unintrusive\", I didn't think of this fallout from an extra\nfile getting reported by ls-files, and this helper function does\nmake sense.  If we were starting from scratch, we probably would\nhave created $HOME that is separate from the test repository in the\ntest framework.  The simplest layout would be to emulate a developer\nwho has repositories under their $HOME, i.e., $TRASH_DIRECTORY stays\nto be the $HOME, but the initial test repository would be created as\na directory inside $TRASH_DIRECTORY instead of using the trash\nitself, or something like that.  It is all water under the bridge\nnow, unless somebody wants an opportunity to work on a non-trivial\nclean-up.\n\nBy the way, when merged to 'seen', with the 'ps/test-set-e-clean'\ntopic already in 'next', many tests (especially the ones with early\ntest_done, like p4 tests in my environment where p4 does not exist)\nseem to fail with WITH_BREAKING_CHANGES turned on.  I don't have\nenough time to be sitting in front of the keyboard to isolate the\ncause, but because this series is one of the topics with biggest\nimpact to the t/ directory that was replaced after the last\nsuccessful run, I thought I should mention it.\n\n"},{"id":"542322","messageId":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.git.1777042877.gitgitgadget@gmail.com","subject":"[PATCH v2 0/8] safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:28Z","receivedAt":"2026-04-26T14:38:39Z","isPatch":true,"body":"This supersedes my earlier series [*1*] which took the approach of adjusting\nindividual tests to access bare repositories explicitly.\n\nAs Junio suggested [*2*], this series instead takes the approach of setting\nsafe.bareRepository=all in the test environment's global config whenever\nWITH_BREAKING_CHANGES is in effect, so that existing tests continue to work\nwithout individual modifications.\n\nImplementing this turned out to require a number of follow-up adjustments,\nbecause writing to $HOME/.gitconfig has side effects beyond the intended\nsetting: $HOME is the trash directory, which doubles as the test\nrepository's working tree, so the file shows up in ls-files and status\noutput, and tests that manipulate $HOME/.gitconfig for their own purposes\ncan clobber or remove the setting. Patches 2 through 7 address these\ninteractions in the affected test scripts.\n\nThe final patch flips the safe.bareRepository default to \"explicit\" under\nWITH_BREAKING_CHANGES.\n\nFootnote [*1*]:\nhttps://lore.kernel.org/git/pull.2076.git.1775140403.gitgitgadget@gmail.com/\n\nFootnote [*2*]: https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/\n\nChanges since v1:\n\n * Made it compatible with Patrick Steinhardt's set -e work.\n\nJohannes Schindelin (8):\n  test-lib: allow bare repository access when breaking changes are\n    enabled\n  t7900: do not let `$HOME/.gitconfig` interfere with XDG tests\n  t1300: remove global config settings injected by test-lib.sh\n  t1305: use `--git-dir=.` for bare repo in include cycle test\n  t5601: restore `.gitconfig` after includeIf test\n  ls-files tests: filter `.gitconfig` from `--others` output\n  status tests: filter `.gitconfig` from status output\n  safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES\n\n Documentation/BreakingChanges.adoc            | 24 +++++++++++++++++\n Documentation/config/safe.adoc                | 10 +++++--\n setup.c                                       |  4 +++\n t/t0035-safe-bare-repository.sh               | 10 +++++--\n t/t1300-config.sh                             |  7 +++++\n t/t1305-config-include.sh                     |  4 +--\n t/t3000-ls-files-others.sh                    |  4 +++\n t/t3001-ls-files-others-exclude.sh            |  3 +++\n t/t3002-ls-files-dashpath.sh                  |  2 ++\n t/t3009-ls-files-others-nonsubmodule.sh       |  1 +\n ...common-prefixes-and-directory-traversal.sh |  3 ++-\n t/t5601-clone.sh                              |  4 ++-\n t/t7060-wtstatus.sh                           |  3 +--\n t/t7061-wtstatus-ignore.sh                    | 27 +++++++++++++++++++\n t/t7064-wtstatus-pv2.sh                       |  1 +\n t/t7104-reset-hard.sh                         |  2 +-\n t/t7508-status.sh                             |  4 +++\n t/t7521-ignored-mode.sh                       |  1 +\n t/t7900-maintenance.sh                        | 12 +++++++--\n t/test-lib-functions.sh                       |  8 ++++++\n t/test-lib.sh                                 | 13 +++++++++\n 21 files changed, 134 insertions(+), 13 deletions(-)\n\n\nbase-commit: 94f057755b7941b321fd11fec1b2e3ca5313a4e0\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2098%2Fdscho%2Fsafe-bare-repo-default-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2098/dscho/safe-bare-repo-default-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/2098\n\nRange-diff vs v1:\n\n 1:  62707b4109 ! 1:  179fcf5369 test-lib: allow bare repository access when breaking changes are enabled\n     @@ Commit message\n          `--exclude-standard` or `git status --ignored`; those are addressed\n          by subsequent commits.\n      \n     +    The `.git/info/exclude` write is guarded by `test -d .git/info`\n     +    rather than using `mkdir -p`, because some tests (e.g. t0008)\n     +    expect to create `.git/info/` themselves and would fail with\n     +    Patrick Steinhardt's `set -e` preparation (ps/test-set-e-clean) if\n     +    the directory already existed. For tests using `TEST_NO_CREATE_REPO`\n     +    (where no `.git/` exists at all), the guard also handles that case.\n     +\n          [1] https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/\n      \n          Original-patch-by: Junio C Hamano <gitster@pobox.com>\n     @@ t/test-lib.sh: cd -P \"$TRASH_DIRECTORY\" || BAIL_OUT \"cannot cd -P to \\\"$TRASH_DI\n      +if test -n \"$WITH_BREAKING_CHANGES\"\n      +then\n      +\tgit config --global safe.bareRepository all &&\n     -+\techo \"/.gitconfig\" >>.git/info/exclude\n     ++\t# Only write to .git/info/exclude when the directory exists\n     ++\t# (i.e. when git init created the repo). If we mkdir -p it\n     ++\t# ourselves, tests that expect to create .git/info/ themselves\n     ++\t# (e.g. t0008) would fail.\n     ++\tif test -d .git/info\n     ++\tthen\n     ++\t\techo \"/.gitconfig\" >>.git/info/exclude\n     ++\tfi\n      +fi\n      +\n       start_test_output \"$0\"\n 2:  d9a2e76f3c = 2:  4dc5151e59 t7900: do not let `$HOME/.gitconfig` interfere with XDG tests\n 3:  9c10e72eed = 3:  7d68155805 t1300: remove global config settings injected by test-lib.sh\n 4:  092ec11621 = 4:  5ff48e0892 t1305: use `--git-dir=.` for bare repo in include cycle test\n 5:  3aca302275 = 5:  ed7294ace3 t5601: restore `.gitconfig` after includeIf test\n 6:  ef57244778 = 6:  556db0eabe ls-files tests: filter `.gitconfig` from `--others` output\n 7:  56fe902644 = 7:  ac4da79eac status tests: filter `.gitconfig` from status output\n 8:  64db45e385 = 8:  73bb1aa171 safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES\n\n-- \ngitgitgadget\n"},{"id":"542323","messageId":"179fcf5369dcccf4c2bef5d991e33bb92cd71bb8.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 1/8] test-lib: allow bare repository access when breaking changes are enabled","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:29Z","receivedAt":"2026-04-26T14:38:40Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nA future patch will change the `safe.bareRepository` default from\n`all` to `explicit` under `WITH_BREAKING_CHANGES`. At that point,\nevery test that operates on a bare repository through implicit\ndiscovery would fail, regardless of whether the test is actually\nabout discovery or about how a specific command behaves once inside\na bare repository.\n\nThe maintainer suggested [1] setting `safe.bareRepository=all` in\nthe test environment's global config whenever `WITH_BREAKING_CHANGES`\nis in effect, rather than adjusting each affected test to access\nbare repositories explicitly (via `--git-dir`, `GIT_DIR`, or\nsimilar). This means the test suite continues to exercise only the\nhistorical default behavior even after the user-facing default\nchanges, relying on a small number of dedicated tests in t0035 to\nvalidate the new, stricter default.\n\nSince `$HOME` points at the trash directory (which doubles as the\ntest repository's working tree), writing to `$HOME/.gitconfig` also\ncreates a file inside the working tree. Exclude it via\n`.git/info/exclude` to limit the fallout, though this does not\nhelp tests that use `git ls-files --others` without\n`--exclude-standard` or `git status --ignored`; those are addressed\nby subsequent commits.\n\nThe `.git/info/exclude` write is guarded by `test -d .git/info`\nrather than using `mkdir -p`, because some tests (e.g. t0008)\nexpect to create `.git/info/` themselves and would fail with\nPatrick Steinhardt's `set -e` preparation (ps/test-set-e-clean) if\nthe directory already existed. For tests using `TEST_NO_CREATE_REPO`\n(where no `.git/` exists at all), the guard also handles that case.\n\n[1] https://lore.kernel.org/git/xmqqse98cc51.fsf@gitster.g/\n\nOriginal-patch-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/test-lib.sh | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/t/test-lib.sh b/t/test-lib.sh\nindex 70fd3e9baf..72ed87b781 100644\n--- a/t/test-lib.sh\n+++ b/t/test-lib.sh\n@@ -1597,6 +1597,19 @@ cd -P \"$TRASH_DIRECTORY\" || BAIL_OUT \"cannot cd -P to \\\"$TRASH_DIRECTORY\\\"\"\n TRASH_DIRECTORY=$(pwd)\n HOME=\"$TRASH_DIRECTORY\"\n \n+if test -n \"$WITH_BREAKING_CHANGES\"\n+then\n+\tgit config --global safe.bareRepository all &&\n+\t# Only write to .git/info/exclude when the directory exists\n+\t# (i.e. when git init created the repo). If we mkdir -p it\n+\t# ourselves, tests that expect to create .git/info/ themselves\n+\t# (e.g. t0008) would fail.\n+\tif test -d .git/info\n+\tthen\n+\t\techo \"/.gitconfig\" >>.git/info/exclude\n+\tfi\n+fi\n+\n start_test_output \"$0\"\n \n # Convenience\n-- \ngitgitgadget\n\n"},{"id":"542324","messageId":"4dc5151e59f289da2195f88c1f8bddfdf71343c6.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 2/8] t7900: do not let `$HOME/.gitconfig` interfere with XDG tests","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:30Z","receivedAt":"2026-04-26T14:38:42Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe XDG config tests for `git maintenance register/unregister`\ncreate a fresh `$XDG_CONFIG_HOME/git/config` and expect git to use\nthat location. However, if `$HOME/.gitconfig` exists (which may\nhappen when test-lib.sh writes global config, e.g. to set\n`safe.bareRepository`), git prefers `$HOME/.gitconfig` over the XDG\nlocation, and the `maintenance.repo` entry ends up in the wrong\nfile.\n\nThis is an inherent consequence of setting global config in\ntest-lib.sh rather than adjusting individual tests: writing any\nentry to `$HOME/.gitconfig` has side effects beyond the intended\nsetting, because the mere existence of that file changes which\nglobal config location git prefers for all subsequent writes.\nIndividual per-test adjustments would not have this interaction.\n\nFix this by overriding `HOME` to a non-existent directory inside the\nsubshells that test XDG behavior. Since these subshells already\noverride `XDG_CONFIG_HOME`, they do not need `$HOME/.gitconfig` at\nall, and the subshell scoping ensures the original `HOME` is\nrestored automatically.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7900-maintenance.sh | 12 ++++++++++--\n 1 file changed, 10 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh\nindex 4700beacc1..4358df0424 100755\n--- a/t/t7900-maintenance.sh\n+++ b/t/t7900-maintenance.sh\n@@ -101,8 +101,12 @@ test_expect_success \"maintenance.autoDetach overrides gc.autoDetach\" '\n test_expect_success 'register uses XDG_CONFIG_HOME config if it exists' '\n \ttest_when_finished rm -r .config/git/config &&\n \t(\n+\t\t# Override HOME so that .gitconfig (which test-lib.sh may\n+\t\t# have created, e.g. to set safe.bareRepository) does not\n+\t\t# take precedence over the XDG location.\n+\t\tHOME=$PWD/must-not-exist &&\n \t\tXDG_CONFIG_HOME=.config &&\n-\t\texport XDG_CONFIG_HOME &&\n+\t\texport HOME XDG_CONFIG_HOME &&\n \t\tmkdir -p $XDG_CONFIG_HOME/git &&\n \t\t>$XDG_CONFIG_HOME/git/config &&\n \t\tgit maintenance register &&\n@@ -124,8 +128,12 @@ test_expect_success 'register does not need XDG_CONFIG_HOME config to exist' '\n test_expect_success 'unregister uses XDG_CONFIG_HOME config if it exists' '\n \ttest_when_finished rm -r .config/git/config &&\n \t(\n+\t\t# Override HOME so that .gitconfig (which test-lib.sh may\n+\t\t# have created, e.g. to set safe.bareRepository) does not\n+\t\t# take precedence over the XDG location.\n+\t\tHOME=$PWD/must-not-exist &&\n \t\tXDG_CONFIG_HOME=.config &&\n-\t\texport XDG_CONFIG_HOME &&\n+\t\texport HOME XDG_CONFIG_HOME &&\n \t\tmkdir -p $XDG_CONFIG_HOME/git &&\n \t\t>$XDG_CONFIG_HOME/git/config &&\n \t\tgit maintenance register &&\n-- \ngitgitgadget\n\n"},{"id":"542325","messageId":"7d68155805f9681f4071ad6d4378960ce36e667b.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 3/8] t1300: remove global config settings injected by test-lib.sh","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:31Z","receivedAt":"2026-04-26T14:38:44Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nSince test-lib.sh now writes `safe.bareRepository=all` to the global\nconfig when `WITH_BREAKING_CHANGES` is in effect, that entry shows\nup in `git config --list` output. Tests in t1300 that expect exact\nconfig contents then fail because of this unexpected extra line.\n\nUnlike the working-tree contamination fixed in the preceding\ncommits, this is not about the file's existence but about its\ncontent leaking into test expectations. Since t1300 does not use\nbare repositories, simply remove the injected setting in a\npreparatory step.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\nAssisted-by: Claude Opus 4.6\n---\n t/t1300-config.sh | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/t/t1300-config.sh b/t/t1300-config.sh\nindex 128971ee12..11fc976f3a 100755\n--- a/t/t1300-config.sh\n+++ b/t/t1300-config.sh\n@@ -11,6 +11,13 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n . ./test-lib.sh\n . \"$TEST_DIRECTORY\"/lib-terminal.sh\n \n+# test-lib.sh may have added global config (e.g. safe.bareRepository)\n+# that would appear in \"git config --list\" output and break tests\n+# that expect exact config contents.\n+test_expect_success 'remove global config from test-lib.sh' '\n+\ttest_might_fail git config --global --unset-all safe.bareRepository\n+'\n+\n for mode in legacy subcommands\n do\n \n-- \ngitgitgadget\n\n"},{"id":"542326","messageId":"5ff48e0892ad0e2c04ed61bafe3178886c267c64.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 4/8] t1305: use `--git-dir=.` for bare repo in include cycle test","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:32Z","receivedAt":"2026-04-26T14:38:46Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEarlier tests in t1305 overwrite `$HOME/.gitconfig` with their own\ncontent as part of testing config includes. This clobbers the\n`safe.bareRepository=all` entry that test-lib.sh writes when\n`WITH_BREAKING_CHANGES` is in effect, causing `git -C cycle config`\nto fail with \"not in a git directory\" when it tries to access the\nbare repository created by `git init --bare cycle`.\n\nUse `--git-dir=.` to access the bare repo explicitly, avoiding the\ndependency on global config for repository discovery.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1305-config-include.sh | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t1305-config-include.sh b/t/t1305-config-include.sh\nindex 6e51f892f3..f3892578e4 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -350,9 +350,9 @@ test_expect_success 'conditional include, onbranch, implicit /** for /' '\n \n test_expect_success 'include cycles are detected' '\n \tgit init --bare cycle &&\n-\tgit -C cycle config include.path cycle &&\n+\tgit -C cycle --git-dir=. config include.path cycle &&\n \tgit config -f cycle/cycle include.path config &&\n-\ttest_must_fail git -C cycle config --get-all test.value 2>stderr &&\n+\ttest_must_fail git -C cycle --git-dir=. config --get-all test.value 2>stderr &&\n \tgrep \"exceeded maximum include depth\" stderr\n '\n \n-- \ngitgitgadget\n\n"},{"id":"542327","messageId":"ed7294ace3770d177a4ee92aaa28013013dcc2f7.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 5/8] t5601: restore `.gitconfig` after includeIf test","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:33Z","receivedAt":"2026-04-26T14:38:48Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nOne test in t5601 overwrites `$HOME/.gitconfig` with an `includeIf`\nconfiguration snippet and removes the file in its cleanup. This\ndestroys the `safe.bareRepository=all` entry that test-lib.sh\nwrites when `WITH_BREAKING_CHANGES` is in effect, causing later\ntests that use `git -C <bare-repo> config` to fail with \"not in a\ngit directory\".\n\nBack up `.gitconfig` before overwriting and restore it in the\ncleanup, so the global config survives into subsequent tests.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t5601-clone.sh | 4 +++-\n 1 file changed, 3 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t5601-clone.sh b/t/t5601-clone.sh\nindex d743d986c4..3dd229c186 100755\n--- a/t/t5601-clone.sh\n+++ b/t/t5601-clone.sh\n@@ -813,7 +813,9 @@ test_expect_success 'clone with includeIf' '\n \ttest_when_finished \"rm -rf repo \\\"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\\\"\" &&\n \tgit clone --bare --no-local src \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n \n-\ttest_when_finished \"rm \\\"$HOME\\\"/.gitconfig\" &&\n+\ttest_when_finished \"cp \\\"$HOME\\\"/.gitconfig.bak \\\n+\t\t\\\"$HOME\\\"/.gitconfig 2>/dev/null || rm -f \\\"$HOME\\\"/.gitconfig\" &&\n+\tcp \"$HOME\"/.gitconfig \"$HOME\"/.gitconfig.bak 2>/dev/null &&\n \tcat >\"$HOME\"/.gitconfig <<-EOF &&\n \t[includeIf \"onbranch:something\"]\n \t\tpath = /does/not/exist.inc\n-- \ngitgitgadget\n\n"},{"id":"542328","messageId":"556db0eabe69f968b9d5f9922ab55d12271cd4d4.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 6/8] ls-files tests: filter `.gitconfig` from `--others` output","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:34Z","receivedAt":"2026-04-26T14:38:49Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe global `safe.bareRepository=all` setting in test-lib.sh is\nwritten to `$HOME/.gitconfig`, which unfortunately lives inside the\ntest repository's working tree. The `.git/info/exclude` entry added\nalongside it handles most commands, but `git ls-files --others`\nwithout `--exclude-standard` does not consult `info/exclude` at\nall, so the file appears in the output.\n\nIdeally, each test that accesses a bare repository would simply\nspecify `--git-dir` or `GIT_DIR` explicitly, which would require no\nglobal config and produce no side effects in the working tree. As\nthat approach was not taken, filter `.gitconfig` from the output\nbefore comparing against expected results. In t7104, the test\nalready uses `--exclude-standard`, so it suffices to switch from\nthe bare `git ls-files -o` to `git ls-files -o --exclude-standard`\nwhich respects the `info/exclude` entry; the other tests\ndeliberately omit `--exclude-standard` because their purpose is to\nverify unfiltered `--others` output.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t3000-ls-files-others.sh                         | 4 ++++\n t/t3001-ls-files-others-exclude.sh                 | 3 +++\n t/t3002-ls-files-dashpath.sh                       | 2 ++\n t/t3009-ls-files-others-nonsubmodule.sh            | 1 +\n t/t3011-common-prefixes-and-directory-traversal.sh | 3 ++-\n t/t7104-reset-hard.sh                              | 2 +-\n t/test-lib-functions.sh                            | 8 ++++++++\n 7 files changed, 21 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t3000-ls-files-others.sh b/t/t3000-ls-files-others.sh\nindex b41e7f0daa..b4f0fbfc55 100755\n--- a/t/t3000-ls-files-others.sh\n+++ b/t/t3000-ls-files-others.sh\n@@ -53,16 +53,19 @@ test_expect_success 'setup: expected output' '\n \n test_expect_success 'ls-files --others' '\n \tgit ls-files --others >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected1 output\n '\n \n test_expect_success 'ls-files --others --directory' '\n \tgit ls-files --others --directory >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected2 output\n '\n \n test_expect_success '--no-empty-directory hides empty directory' '\n \tgit ls-files --others --directory --no-empty-directory >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected3 output\n '\n \n@@ -70,6 +73,7 @@ test_expect_success 'ls-files --others handles non-submodule .git' '\n \tmkdir not-a-submodule &&\n \techo foo >not-a-submodule/.git &&\n \tgit ls-files -o >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expected1 output\n '\n \ndiff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh\nindex 4b67646285..202fb8d9ea 100755\n--- a/t/t3001-ls-files-others-exclude.sh\n+++ b/t/t3001-ls-files-others-exclude.sh\n@@ -72,6 +72,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -84,6 +85,7 @@ test_expect_success 'git ls-files --others with \\r\\n line endings.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -99,6 +101,7 @@ test_expect_success 'git ls-files --others with various exclude options.' '\n        --exclude-per-directory=.gitignore \\\n        --exclude-from=.git/ignore \\\n \t>output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \ndiff --git a/t/t3002-ls-files-dashpath.sh b/t/t3002-ls-files-dashpath.sh\nindex 31462cb441..6acaadbd67 100755\n--- a/t/t3002-ls-files-dashpath.sh\n+++ b/t/t3002-ls-files-dashpath.sh\n@@ -24,6 +24,7 @@ test_expect_success 'setup' '\n test_expect_success 'git ls-files without path restriction.' '\n \ttest_when_finished \"rm -f expect\" &&\n \tgit ls-files --others >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-\\EOF &&\n \t--\n \t-foo\n@@ -63,6 +64,7 @@ test_expect_success 'git ls-files with path restriction with -- --.' '\n test_expect_success 'git ls-files with no path restriction.' '\n \ttest_when_finished \"rm -f expect\" &&\n \tgit ls-files --others -- >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-\\EOF &&\n \t--\n \t-foo\ndiff --git a/t/t3009-ls-files-others-nonsubmodule.sh b/t/t3009-ls-files-others-nonsubmodule.sh\nindex 963f3462b7..dc990c277b 100755\n--- a/t/t3009-ls-files-others-nonsubmodule.sh\n+++ b/t/t3009-ls-files-others-nonsubmodule.sh\n@@ -36,6 +36,7 @@ test_expect_success 'setup: directories' '\n \n test_expect_success 'ls-files --others handles untracked git repositories' '\n \tgit ls-files -o >output &&\n+\ttest_filter_gitconfig output &&\n \tcat >expect <<-EOF &&\n \tnonrepo-untracked-file/untracked\n \toutput\ndiff --git a/t/t3011-common-prefixes-and-directory-traversal.sh b/t/t3011-common-prefixes-and-directory-traversal.sh\nindex 3da5b2b6e7..455e97954d 100755\n--- a/t/t3011-common-prefixes-and-directory-traversal.sh\n+++ b/t/t3011-common-prefixes-and-directory-traversal.sh\n@@ -26,7 +26,7 @@ test_expect_success 'setup' '\n '\n \n test_expect_success 'git ls-files -o shows the right entries' '\n-\tcat <<-EOF >expect &&\n+\tcat >expect <<-EOF &&\n \t.gitignore\n \tactual\n \tan_ignored_dir/ignored\n@@ -39,6 +39,7 @@ test_expect_success 'git ls-files -o shows the right entries' '\n \tuntracked_repo/\n \tEOF\n \tgit ls-files -o >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t7104-reset-hard.sh b/t/t7104-reset-hard.sh\nindex 7948ec392b..c23d6e3f52 100755\n--- a/t/t7104-reset-hard.sh\n+++ b/t/t7104-reset-hard.sh\n@@ -21,7 +21,7 @@ test_expect_success setup '\n \trm -f hello &&\n \tmkdir -p hello &&\n \t>hello/world &&\n-\ttest \"$(git ls-files -o)\" = hello/world\n+\ttest \"$(git ls-files -o --exclude-standard)\" = hello/world\n \n '\n \ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex f3af10fb7e..0505da78e8 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -2069,3 +2069,11 @@ test_trailing_hash () {\n test_redact_non_printables () {\n     tr -d \"\\n\\r\" | tr \"[\\001-\\040][\\177-\\377]\" \".\"\n }\n+\n+# Remove .gitconfig entries from a file in place.  test-lib.sh may\n+# create $HOME/.gitconfig (e.g. to set safe.bareRepository) which\n+# can appear in ls-files or status output.\n+test_filter_gitconfig () {\n+\tsed \"/\\\\.gitconfig/d\" \"$1\" >\"$1.filtered\" &&\n+\tmv \"$1.filtered\" \"$1\"\n+}\n-- \ngitgitgadget\n\n"},{"id":"542329","messageId":"ac4da79eac90aa062fd696f29c61b639030c1d41.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 7/8] status tests: filter `.gitconfig` from status output","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:35Z","receivedAt":"2026-04-26T14:38:51Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nSince test-lib.sh creates `$HOME/.gitconfig` when\n`WITH_BREAKING_CHANGES` is in effect, the file appears in `git\nstatus` output as either untracked (`?? .gitconfig`) or ignored\n(`!! .gitconfig` / `! .gitconfig`, depending on porcelain version),\nbecause the `.git/info/exclude` entry causes git to treat it as an\nignored file rather than hiding it entirely.\n\nIn t7061 and t7521, which are pervasively affected, introduce a\n`filter_gitconfig` helper that strips all status-prefix variants of\n`.gitconfig` from the output before comparison. In the remaining\nscripts (t7060, t7064, t7508), apply targeted adjustments.\n\nAssisted-by: Claude Opus 4.6\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7060-wtstatus.sh        |  3 +--\n t/t7061-wtstatus-ignore.sh | 27 +++++++++++++++++++++++++++\n t/t7064-wtstatus-pv2.sh    |  1 +\n t/t7508-status.sh          |  4 ++++\n t/t7521-ignored-mode.sh    |  1 +\n 5 files changed, 34 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t7060-wtstatus.sh b/t/t7060-wtstatus.sh\nindex 0f4344c55e..942ddbbf0e 100755\n--- a/t/t7060-wtstatus.sh\n+++ b/t/t7060-wtstatus.sh\n@@ -9,6 +9,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n \n test_expect_success setup '\n \tgit config --global advice.statusuoption false &&\n+\techo \"/.gitconfig\" >>.git/info/exclude &&\n \ttest_commit A &&\n \ttest_commit B oneside added &&\n \tgit checkout A^0 &&\n@@ -221,7 +222,6 @@ test_expect_success 'status --branch with detached HEAD' '\n \tgit status --branch --porcelain >actual &&\n \tcat >expected <<-EOF &&\n \t## HEAD (no branch)\n-\t?? .gitconfig\n \t?? actual\n \t?? expect\n \t?? expected\n@@ -237,7 +237,6 @@ test_expect_success 'status --porcelain=v1 --branch with detached HEAD' '\n \tgit status --branch --porcelain=v1 >actual &&\n \tcat >expected <<-EOF &&\n \t## HEAD (no branch)\n-\t?? .gitconfig\n \t?? actual\n \t?? expect\n \t?? expected\ndiff --git a/t/t7061-wtstatus-ignore.sh b/t/t7061-wtstatus-ignore.sh\nindex 2f9bea9793..14ddaba2f3 100755\n--- a/t/t7061-wtstatus-ignore.sh\n+++ b/t/t7061-wtstatus-ignore.sh\n@@ -18,6 +18,7 @@ test_expect_success 'status untracked directory with --ignored' '\n \t: >untracked/ignored &&\n \t: >untracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -27,6 +28,7 @@ test_expect_success 'same with gitignore starting with BOM' '\n \t: >untracked/ignored &&\n \t: >untracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -40,18 +42,22 @@ test_expect_success 'status untracked files --ignored with pathspec (no match)'\n test_expect_success 'status untracked files --ignored with pathspec (literal match)' '\n \tgit status --porcelain --ignored -- untracked/ignored >actual &&\n \techo \"!! untracked/ignored\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \tgit status --porcelain --ignored -- untracked/uncommitted >actual &&\n \techo \"?? untracked/uncommitted\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n test_expect_success 'status untracked files --ignored with pathspec (glob match)' '\n \tgit status --porcelain --ignored -- untracked/i\\* >actual &&\n \techo \"!! untracked/ignored\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \tgit status --porcelain --ignored -- untracked/u\\* >actual &&\n \techo \"?? untracked/uncommitted\" >expected &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -65,6 +71,7 @@ EOF\n \n test_expect_success 'status untracked directory with --ignored -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n cat >expected <<\\EOF\n@@ -76,9 +83,11 @@ test_expect_success 'status of untracked directory with --ignored works with or\n \tgit status --porcelain --ignored >tmp &&\n \tgrep untracked/ tmp >actual &&\n \trm tmp &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual &&\n \n \tgit status --porcelain --ignored untracked/ >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -89,6 +98,7 @@ EOF\n \n test_expect_success 'status prefixed untracked sub-directory with --ignored -u' '\n \tgit status --porcelain --ignored -u untracked/ >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -104,6 +114,7 @@ test_expect_success 'status ignored directory with --ignore' '\n \tmkdir ignored &&\n \t: >ignored/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -116,6 +127,7 @@ EOF\n \n test_expect_success 'status ignored directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -130,6 +142,7 @@ test_expect_success 'status empty untracked directory with --ignore' '\n \tmkdir untracked-ignored &&\n \tmkdir untracked-ignored/test &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -141,6 +154,7 @@ EOF\n \n test_expect_success 'status empty untracked directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -155,6 +169,7 @@ test_expect_success 'status untracked directory with ignored files with --ignore\n \t: >untracked-ignored/ignored &&\n \t: >untracked-ignored/test/ignored &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -168,6 +183,7 @@ EOF\n \n test_expect_success 'status untracked directory with ignored files with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -185,6 +201,7 @@ test_expect_success 'status ignored tracked directory with --ignore' '\n \tgit commit -m. &&\n \techo \"tracked\" >.gitignore &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -196,6 +213,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -208,6 +226,7 @@ EOF\n test_expect_success 'status ignored tracked directory and ignored file with --ignore' '\n \techo \"committed\" >>.gitignore &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -219,6 +238,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory and ignored file with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -233,6 +253,7 @@ test_expect_success 'status ignored tracked directory and uncommitted file with\n \techo \"tracked\" >.gitignore &&\n \t: >tracked/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -245,6 +266,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory and uncommitted file with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -260,6 +282,7 @@ test_expect_success 'status ignored tracked directory with uncommitted file in u\n \tmkdir tracked/ignored &&\n \t: >tracked/ignored/uncommitted &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -272,6 +295,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with uncommitted file in untracked subdir with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -287,6 +311,7 @@ test_expect_success 'status ignored tracked directory with uncommitted file in t\n \tgit add -f tracked/ignored/committed &&\n \tgit commit -m. &&\n \tgit status --porcelain --ignored >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -299,6 +324,7 @@ EOF\n \n test_expect_success 'status ignored tracked directory with uncommitted file in tracked subdir with --ignore -u' '\n \tgit status --porcelain --ignored -u >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \n@@ -310,6 +336,7 @@ test_expect_success 'status ignores submodule in excluded directory' '\n \tgit init tracked/submodule &&\n \ttest_commit -C tracked/submodule initial &&\n \tgit status --porcelain --ignored -u tracked/submodule >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expected actual\n '\n \ndiff --git a/t/t7064-wtstatus-pv2.sh b/t/t7064-wtstatus-pv2.sh\nindex 8bbc5ce6d9..be6c931a96 100755\n--- a/t/t7064-wtstatus-pv2.sh\n+++ b/t/t7064-wtstatus-pv2.sh\n@@ -231,6 +231,7 @@ test_expect_success 'ignored files are printed with --ignored' '\n \tEOF\n \n \tgit status --porcelain=v2 --ignored --untracked-files=all >actual &&\n+\ttest_filter_gitconfig actual &&\n \ttest_cmp expect actual\n '\n \ndiff --git a/t/t7508-status.sh b/t/t7508-status.sh\nindex a5e21bf8bf..5f76ec62d8 100755\n--- a/t/t7508-status.sh\n+++ b/t/t7508-status.sh\n@@ -263,6 +263,7 @@ test_expect_success 'status with gitignore' '\n \t!! untracked\n \tEOF\n \tgit status -s --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output &&\n \n \tcat >expect <<\\EOF &&\n@@ -296,6 +297,7 @@ Ignored files:\n \n EOF\n \tgit status --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n@@ -328,6 +330,7 @@ test_expect_success 'status with gitignore (nothing untracked)' '\n \t!! untracked\n \tEOF\n \tgit status -s --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output &&\n \n \tcat >expect <<\\EOF &&\n@@ -358,6 +361,7 @@ Ignored files:\n \n EOF\n \tgit status --ignored >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \ndiff --git a/t/t7521-ignored-mode.sh b/t/t7521-ignored-mode.sh\nindex a88b02b06e..7ea0b0d2f2 100755\n--- a/t/t7521-ignored-mode.sh\n+++ b/t/t7521-ignored-mode.sh\n@@ -30,6 +30,7 @@ test_expect_success 'Verify behavior of status on directories with ignored files\n \t\tdir/ignored/ignored_1.ign dir/ignored/ignored_2.ign &&\n \n \tgit status --porcelain=v2 --ignored=matching --untracked-files=all >output &&\n+\ttest_filter_gitconfig output &&\n \ttest_cmp expect output\n '\n \n-- \ngitgitgadget\n\n"},{"id":"542330","messageId":"73bb1aa17141077cf7cd1004feeee36b05886979.1777214316.git.gitgitgadget@gmail.com","threadId":"65549","inReplyTo":"pull.2098.v2.git.1777214316.gitgitgadget@gmail.com","subject":"[PATCH v2 8/8] safe.bareRepository: default to \"explicit\" with WITH_BREAKING_CHANGES","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2026-04-26T14:38:36Z","receivedAt":"2026-04-26T14:38:53Z","isPatch":true,"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen an attacker can convince a user to clone a crafted repository\nthat contains an embedded bare repository with malicious hooks, any Git\ncommand the user runs after entering that subdirectory will discover\nthe bare repository and execute the hooks. The user does not even need\nto run a Git command explicitly: many shell prompts run `git status`\nin the background to display branch and dirty state information, and\n`git status` in turn may invoke the fsmonitor hook if so configured,\nmaking the user vulnerable the moment they `cd` into the directory. The\n`safe.bareRepository` configuration variable (introduced in 8959555cee7e\n(setup_git_directory(): add an owner check for the top-level directory,\n2022-03-02)) already provides protection against this attack vector by\nallowing users to set it to \"explicit\", but the default remained \"all\"\nfor backwards compatibility.\n\nSince Git 3.0 is the natural point to change defaults to safer\nvalues, flip the default from \"all\" to \"explicit\" when built with\n`WITH_BREAKING_CHANGES`. This means Git will refuse to work with bare\nrepositories that are discovered implicitly by walking up the directory\ntree. Bare repositories specified via `--git-dir` or `GIT_DIR` continue\nto work, and directories that look like `.git`, worktrees, or submodule\ndirectories are unaffected (the existing `is_implicit_bare_repo()`\nwhitelist handles those cases).\n\nUsers who rely on implicit bare repository discovery can restore the\nprevious behavior by setting `safe.bareRepository=all` in their global\nor system configuration.\n\nThe test for the \"safe.bareRepository in the repository\" scenario\nneeded a more involved fix: it writes a `safe.bareRepository=all`\nentry into the bare repository's own config to verify that repo-local\nconfig does not override the protected (global) setting. Previously,\n`test_config -C` was used to write that entry, but its cleanup runs `git\n-C <bare-repo> config --unset`, which itself fails when the default is\n\"explicit\" and the global config has already been cleaned up. Switching\nto direct git config --file access avoids going through repository\ndiscovery entirely.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n Documentation/BreakingChanges.adoc | 24 ++++++++++++++++++++++++\n Documentation/config/safe.adoc     | 10 ++++++++--\n setup.c                            |  4 ++++\n t/t0035-safe-bare-repository.sh    | 10 ++++++++--\n 4 files changed, 44 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/BreakingChanges.adoc b/Documentation/BreakingChanges.adoc\nindex af59c43f42..73bb939359 100644\n--- a/Documentation/BreakingChanges.adoc\n+++ b/Documentation/BreakingChanges.adoc\n@@ -216,6 +216,30 @@ would be significant, we may decide to defer this change to a subsequent minor\n release. This evaluation will also take into account our own experience with\n how painful it is to keep Rust an optional component.\n \n+* The default value of `safe.bareRepository` will change from `all` to\n+  `explicit`. It is all too easy for an attacker to trick a user into cloning a\n+  repository that contains an embedded bare repository with malicious hooks\n+  configured. If the user enters that subdirectory and runs any Git command, Git\n+  discovers the bare repository and the hooks fire. The user does not even need\n+  to run a Git command explicitly: many shell prompts run `git status` in the\n+  background to display branch and dirty state information, and `git status` in\n+  turn may invoke the fsmonitor hook if so configured, making the user\n+  vulnerable the moment they `cd` into the directory. The `safe.bareRepository`\n+  configuration variable was introduced in 8959555cee (setup_git_directory():\n+  add an owner check for the top-level directory, 2022-03-02) with a default of\n+  `all` to preserve backwards compatibility.\n++\n+Changing the default to `explicit` means that Git will refuse to work with bare\n+repositories that are discovered implicitly by walking up the directory tree.\n+Bare repositories specified explicitly via the `--git-dir` command-line option\n+or the `GIT_DIR` environment variable continue to work regardless of this\n+setting. Repositories that look like a `.git` directory, a worktree, or a\n+submodule directory are also unaffected.\n++\n+Users who rely on implicit discovery of bare repositories can restore the\n+previous behavior by setting `safe.bareRepository=all` in their global or\n+system configuration.\n+\n === Removals\n \n * Support for grafting commits has long been superseded by git-replace(1).\ndiff --git a/Documentation/config/safe.adoc b/Documentation/config/safe.adoc\nindex 2d45c98b12..5b1690aebe 100644\n--- a/Documentation/config/safe.adoc\n+++ b/Documentation/config/safe.adoc\n@@ -2,10 +2,12 @@ safe.bareRepository::\n \tSpecifies which bare repositories Git will work with. The currently\n \tsupported values are:\n +\n-* `all`: Git works with all bare repositories. This is the default.\n+* `all`: Git works with all bare repositories. This is the default in\n+  Git 2.x.\n * `explicit`: Git only works with bare repositories specified via\n   the top-level `--git-dir` command-line option, or the `GIT_DIR`\n-  environment variable (see linkgit:git[1]).\n+  environment variable (see linkgit:git[1]). This will be the default\n+  in Git 3.0.\n +\n If you do not use bare repositories in your workflow, then it may be\n beneficial to set `safe.bareRepository` to `explicit` in your global\n@@ -13,6 +15,10 @@ config. This will protect you from attacks that involve cloning a\n repository that contains a bare repository and running a Git command\n within that directory.\n +\n+If you use bare repositories regularly and want to preserve the current\n+behavior after upgrading to Git 3.0, set `safe.bareRepository` to `all`\n+in your global or system config.\n++\n This config setting is only respected in protected configuration (see\n <<SCOPES>>). This prevents untrusted repositories from tampering with\n this value.\ndiff --git a/setup.c b/setup.c\nindex 7ec4427368..17c0662076 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -1485,7 +1485,11 @@ static int allowed_bare_repo_cb(const char *key, const char *value,\n \n static enum allowed_bare_repo get_allowed_bare_repo(void)\n {\n+#ifdef WITH_BREAKING_CHANGES\n+\tenum allowed_bare_repo result = ALLOWED_BARE_REPO_EXPLICIT;\n+#else\n \tenum allowed_bare_repo result = ALLOWED_BARE_REPO_ALL;\n+#endif\n \tgit_protected_config(allowed_bare_repo_cb, &result);\n \treturn result;\n }\ndiff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh\nindex ae7ef092ab..1d3d19f5b4 100755\n--- a/t/t0035-safe-bare-repository.sh\n+++ b/t/t0035-safe-bare-repository.sh\n@@ -44,11 +44,16 @@ test_expect_success 'setup an embedded bare repo, secondary worktree and submodu\n \ttest_path_is_dir outer-repo/.git/modules/subn\n '\n \n-test_expect_success 'safe.bareRepository unset' '\n+test_expect_success !WITH_BREAKING_CHANGES 'safe.bareRepository unset' '\n \ttest_unconfig --global safe.bareRepository &&\n \texpect_accepted_implicit -C outer-repo/bare-repo\n '\n \n+test_expect_success WITH_BREAKING_CHANGES 'safe.bareRepository unset (defaults to explicit)' '\n+\ttest_unconfig --global safe.bareRepository &&\n+\texpect_rejected -C outer-repo/bare-repo\n+'\n+\n test_expect_success 'safe.bareRepository=all' '\n \ttest_config_global safe.bareRepository all &&\n \texpect_accepted_implicit -C outer-repo/bare-repo\n@@ -63,7 +68,8 @@ test_expect_success 'safe.bareRepository in the repository' '\n \t# safe.bareRepository must not be \"explicit\", otherwise\n \t# git config fails with \"fatal: not in a git directory\" (like\n \t# safe.directory)\n-\ttest_config -C outer-repo/bare-repo safe.bareRepository all &&\n+\ttest_when_finished \"git config --file outer-repo/bare-repo/config --unset safe.bareRepository\" &&\n+\tgit config --file outer-repo/bare-repo/config safe.bareRepository all &&\n \ttest_config_global safe.bareRepository explicit &&\n \texpect_rejected -C outer-repo/bare-repo\n '\n-- \ngitgitgadget\n"}]}