{"thread":{"id":"64552","subject":"[PATCH 00/10] Prepare Git's test suite for symbolic link support on Windows","startedAt":"2025-11-29T18:28:30Z","lastAt":"2025-12-17T23:19:47Z","messageCount":68,"participants":["Johannes Schindelin via GitGitGadget","Junio C Hamano","Eric Sunshine","Patrick Steinhardt","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":10},"messages":[{"id":"531436","messageId":"pull.2009.git.1764440906.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":null,"subject":"[PATCH 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:16Z","receivedAt":"2025-11-29T18:28:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git for Windows has supported symbolic links for quite some time: In\nhttps://github.com/git-for-windows/git/pull/156, this support was introduced\nalready into Git for Windows v2.4.2.windows.1 in May 2015.\n\nHowever, the Git for Windows CI never ran the test suite with symbolic link\nsupport because the MSYS2 runtime (i.e. the POSIX emulation layer required\nto run Git's test suite because the latter is written in Unix shell script)\ndoes not support symbolic links right out of the box. This is for historical\nreasons: Symbolic link support was introduced in Windows 7, where these\nlinks could only be created by administrators by default, and it took until\nWindows 10 Build 14972 that at least in Developer Mode, non-administrators\nwould be permitted to create them.\n\nThe MSYS2 runtime does have some sort of support for symbolic links,\nalthough with caveats: seeing as it expects the inputs as Unix-like paths,\nbut the outputs need to be Win32 symbolic links pointing to Win32 paths,\nsome normalization has to be performed in the process. This leads to\nsometimes surprising behavior e.g. when a link target like a/b/.. is\nnormalized to a.\n\nIt has been a minute or three since the time when Windows versions without\nsymbolic link support were common, therefore there are plans to turn on that\nsupport in the MSYS2 runtime on these Windows versions by default, see\nhttps://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n\nTo prepare for this, I am working toward upstreaming Git for Windows' own\nsupport for symbolic links. And to prepare for that, in turn, I am hereby\ncontributing preemptively the fixes required to eventually let Git's test\nsuite pass when both MSYS2 runtime and Git support symbolic links.\n\nAs a bonus, this patch series also contains fixes for the Perl tests (which\nwere broken for a few years, unnoticed because the CI runs need to save on\nruntime and therefore skip the Perl tests because the consume a lot of\ntime).\n\nJohannes Schindelin (10):\n  t9700: accommodate for Windows paths\n  apply: symbolic links lack a \"trustable executable bit\"\n  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  t0001: handle `diff --no-index` gracefully\n  t0301: another fix for Windows compatibility\n  t0600: fix incomplete prerequisite for a test case\n  t1006: accommodate for symlink support in MSYS2\n  t1305: skip symlink tests that do not apply to Windows\n  t6423: introduce Windows-specific handling for symlinking to /dev/null\n  t7800: work around the MSYS path conversion on Windows\n\n apply.c                             |  2 +-\n compat/mingw.c                      | 14 ++++++++++++++\n t/t0001-init.sh                     |  5 ++++-\n t/t0301-credential-cache.sh         |  3 ++-\n t/t0600-reffiles-backend.sh         |  2 +-\n t/t1006-cat-file.sh                 | 24 +++++++++++++++++-------\n t/t1305-config-include.sh           |  4 ++--\n t/t6423-merge-rename-directories.sh |  9 +++++++--\n t/t7800-difftool.sh                 |  8 ++++----\n t/t9700/test.pl                     |  9 +++++++--\n 10 files changed, 59 insertions(+), 21 deletions(-)\n\n\nbase-commit: 9a2fb147f2c61d0cab52c883e7e26f5b7948e3ed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2009%2Fdscho%2Fprepare-the-test-suite-for-symlink-support-on-windows-v1\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2009/dscho/prepare-the-test-suite-for-symlink-support-on-windows-v1\nPull-Request: https://github.com/gitgitgadget/git/pull/2009\n-- \ngitgitgadget\n"},{"id":"531437","messageId":"2d329837e34a88cfe28be728fe24bb5a2c6a9752.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 01/10] t9700: accommodate for Windows paths","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:17Z","receivedAt":"2025-11-29T18:28:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEver since fe53bbc9beb (Git.pm: Always set Repository to absolute path\nif autodetecting, 2009-05-07), the t9700 test _must_ fail on Windows\nbecause of that age-old Unix paths vs Windows paths problem.\n\nThe underlying root cause is that Git cannot run with a regular Win32\nvariant of Perl, the assumption that every path is a Unix path is just\ntoo strong in Git's Perl code.\n\nAs a consequence, Git for Windows is basically stuck with using the\nMSYS2 variant of Perl which uses a POSIX emulation layer (which is a\nfriendly fork of Cygwin) _and_ a best-effort Unix <-> Windows paths\nconversion whenever crossing the boundary between MSYS2 and regular\nWin32 processes. It is best effort only, though, using heuristics to\nautomagically convert correctly in most cases, but not in all cases.\n\nIn the context of this here patch, this means that asking `git.exe` for\nthe absolute path of the `.git/` directory will return a Win32 path\nbecause `git.exe` is a regular Win32 executable that has no idea about\nUnix-ish paths. But above-mentioned commit introduced a test that wants\nto verify that this path is identical to the one that the Git Perl\nmodule reports (which refuses to use Win32 paths and uses Unix-ish paths\ninstead). Obviously, this must fail because no heuristics can kick in at\nthat layer.\n\nThis test failure has not even been caught when Git introduced Windows\nsupport in its CI definition in 2e90484eb4a (ci: add a Windows job to\nthe Azure Pipelines definition, 2019-01-29), as all tests relying on\nPerl had to be disabled even from the start (because the CI runs would\notherwise have resulted in prohibitively long runtimes, not because\nWindows is super slow per se, but because Git's test suite keeps\ninsisting on using technology that requires a POSIX emulation layer,\nwhich _is_ super slow on Windows).\n\nTo work around this failure, let's use the `cygpath` utility to convert\nthe absolute `gitdir` path into the form that the Perl code expects.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t9700/test.pl | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9700/test.pl b/t/t9700/test.pl\nindex 58a9b328d5..570b0c5680 100755\n--- a/t/t9700/test.pl\n+++ b/t/t9700/test.pl\n@@ -117,7 +117,12 @@ close TEMPFILE;\n unlink $tmpfile;\n \n # paths\n-is($r->repo_path, $abs_repo_dir . \"/.git\", \"repo_path\");\n+my $abs_git_dir = $abs_repo_dir . \"/.git\";\n+if ($^O eq 'msys' or $^O eq 'cygwin') {\n+  $abs_git_dir = `cygpath -am \"$abs_repo_dir/.git\"`;\n+  $abs_git_dir =~ s/\\r?\\n?$//;\n+}\n+is($r->repo_path, $abs_git_dir, \"repo_path\");\n is($r->wc_path, $abs_repo_dir . \"/\", \"wc_path\");\n is($r->wc_subdir, \"\", \"wc_subdir initial\");\n $r->wc_chdir(\"directory1\");\n@@ -127,7 +132,7 @@ is($r->config(\"test.string\"), \"value\", \"config after wc_chdir\");\n # Object generation in sub directory\n chdir(\"directory2\");\n my $r2 = Git->repository();\n-is($r2->repo_path, $abs_repo_dir . \"/.git\", \"repo_path (2)\");\n+is($r2->repo_path, $abs_git_dir, \"repo_path (2)\");\n is($r2->wc_path, $abs_repo_dir . \"/\", \"wc_path (2)\");\n is($r2->wc_subdir, \"directory2/\", \"wc_subdir initial (2)\");\n \n-- \ngitgitgadget\n\n"},{"id":"531438","messageId":"b97afa9a5c28aa89fd94f210a0dec5de891eb221.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 02/10] apply: symbolic links lack a \"trustable executable bit\"","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:18Z","receivedAt":"2025-11-29T18:28:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen 0482c32c334b (apply: ignore working tree filemode when\n!core.filemode, 2023-12-26) fixed `git apply` to stop warning about\nexecutable files, it inadvertently changed the code flow also for\nsymbolic links and directories.\n\nLet's narrow the scope of the special `!trust_executable_git` code path\nto apply only to regular files.\n\nThis is needed to let t4115.5(symlink escape when creating new files)\npass on Windows when symbolic link support is enabled in the MSYS2\nruntime.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex a2ceb3fb40..de5750354a 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3779,7 +3779,7 @@ static int check_preimage(struct apply_state *state,\n \t\tif (*ce && !(*ce)->ce_mode)\n \t\t\tBUG(\"ce_mode == 0 for path '%s'\", old_name);\n \n-\t\tif (trust_executable_bit)\n+\t\tif (trust_executable_bit || !S_ISREG(st->st_mode))\n \t\t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n \t\telse if (*ce)\n \t\t\tst_mode = (*ce)->ce_mode;\n-- \ngitgitgadget\n\n"},{"id":"531439","messageId":"96e279f50ebc26084095e781cf58db233fa05b74.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:19Z","receivedAt":"2025-11-29T18:28:34Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `_wopen()` function would gladly follow a symbolic link to a\nnon-existent file and create it when given above-mentioned flags.\n\nGit expects the `open()` call to fail, though. So let's add yet another\nwork-around to pretend that Windows behaves like Linux.\n\nThis is required to let t4115.8(--reject removes .rej symlink if it\nexists) pass on Windows when enabling the MSYS2 runtime's symbolic link\nsupport.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.c | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 736a07a028..9fbf12a3d3 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n \twchar_t wfilename[MAX_PATH];\n \topen_fn_t open_fn;\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n \n \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n \n@@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n \telse if (xutftowcs_path(wfilename, filename) < 0)\n \t\treturn -1;\n \n+\t/*\n+\t * When `symlink` exists and is a symbolic link pointing to a\n+\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n+\t * create that file. Not what we want: Linux would say `EEXIST`\n+\t * in that instance, which is therefore what Git expects.\n+\t */\n+\tif (create &&\n+\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n+\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n+\t\terrno = EEXIST;\n+\t\treturn -1;\n+\t}\n+\n \tfd = open_fn(wfilename, oflags, mode);\n \n \t/*\n-- \ngitgitgadget\n\n"},{"id":"531440","messageId":"3be9594e80c37b2b393f5883a173694ab6793813.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:20Z","receivedAt":"2025-11-29T18:28:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe test case 're-init to move gitdir symlink' wants to compare the\ncontents of `newdir/.git`, which is a symbolic link pointing to a file.\nHowever, `git diff --no-index`, which is used by `test_cmp` on Windows,\ndoes not resolve symlinks; It shows the symlink _target_ instead (with a\nfile mode of 120000). That is totally unexpected by the test case, which\nas a consequence fails, meaning that it's a bug in the test case itself.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0001-init.sh | 5 ++++-\n 1 file changed, 4 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 618da080dc..2f38e09b58 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -425,7 +425,10 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n \tgit init --separate-git-dir ../realgitdir\n \t) &&\n \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n-\ttest_cmp expected newdir/.git &&\n+\tcase \"$GIT_TEST_CMP\" in\n+\t*--no-index*) ;; # git diff --no-index does not resolve symlinks\n+\t*) test_cmp expected newdir/.git;;\n+\tesac &&\n \ttest_cmp expected newdir/here &&\n \ttest_path_is_dir realgitdir/refs\n '\n-- \ngitgitgadget\n\n"},{"id":"531441","messageId":"c59a5f24789cff55819caf92d828256f2291b3ff.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:21Z","receivedAt":"2025-11-29T18:28:36Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nJust like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\nsuite because that would fail on Windows (because Windows has a much\nmore powerful permission system that cannot be mapped into the simpler\nuser/group/other read/write/execute model).\n\nThere was one forgotten instance of this which was hidden by a `SYMLINK`\nprerequisite. Currently, this prevents this test case from being\nexecuted on Windows, but with the upcoming support for symbolic links,\nit would become a problem.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0301-credential-cache.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\nindex dc30289f75..6f7cfd9e33 100755\n--- a/t/t0301-credential-cache.sh\n+++ b/t/t0301-credential-cache.sh\n@@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n \t\trmdir \\\"\\$HOME/dir/\\\" &&\n \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n \t\" &&\n-\tmkdir -p -m 700 \"$HOME/dir/\" &&\n+\tmkdir -p \"$HOME/dir/\" &&\n+\tchmod 700 \"$HOME/dir/\" &&\n \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n \tcheck approve cache <<-\\EOF &&\n \tprotocol=https\n-- \ngitgitgadget\n\n"},{"id":"531442","messageId":"0866db0a17d88016617e7e626dc032af599679c8.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 06/10] t0600: fix incomplete prerequisite for a test case","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:22Z","receivedAt":"2025-11-29T18:28:38Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe 'symref transaction supports symlinks' test case is guarded by the\n`SYMLINK` prerequisite because `core.prefersymlinkrefs = true` requires\nsymbolic links to be supported.\n\nHowever, the `preferSymlinkRefs` feature is not supported on Windows,\ntherefore this test case needs the `MINGW` prerequisite, too.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0600-reffiles-backend.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\nindex b11126ed47..74bfa2e9ba 100755\n--- a/t/t0600-reffiles-backend.sh\n+++ b/t/t0600-reffiles-backend.sh\n@@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '\n \tesac\n '\n \n-test_expect_success SYMLINKS 'symref transaction supports symlinks' '\n+test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '\n \ttest_when_finished \"git symbolic-ref -d TEST_SYMREF_HEAD\" &&\n \tgit update-ref refs/heads/new @ &&\n \ttest_config core.prefersymlinkrefs true &&\n-- \ngitgitgadget\n\n"},{"id":"531443","messageId":"8a7c68b629f64a3fd8c08f54b5e8693f6568885c.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:23Z","receivedAt":"2025-11-29T18:28:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe MSYS2 runtime (which inherits this trait from the Cygwin runtime,\nand which is used by Git for Windows' Bash to emulate POSIX\nfunctionality on Windows, the same Bash that is also used to run Git's\ntest suite on Windows) has a mode where it can create native symbolic\nlinks on Windows.\n\nNaturally, this is a bit of a strange feature, given that Cygwin goes\nout of its way to support Unix-like paths even if no Win32 program\nunderstands those, and the symbolic links have to use Win32 paths\ninstead (which Win32 programs understand very well).\n\nAs a consequence, the symbolic link targets get normalized before the\nlinks are created.\n\nThis results in certain quirks that Git's test suite is ill equipped to\naccommodate (because Git's test suite expects to be able to use\nUnix-like paths even on Windows).\n\nThe test script t1006-cat-file.sh contains two prime examples, two test\ncases that need to skip a couple assertions because they are simply\nwrong in the context of Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1006-cat-file.sh | 24 +++++++++++++++++-------\n 1 file changed, 17 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 1f61b666a7..0eee3bb878 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-\n \techo .. >>expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual &&\n-\techo symlink 3 >expect &&\n-\techo ../ >>expect &&\n+\tif test_have_prereq MINGW,SYMLINKS\n+\tthen\n+\t\ttest_write_lines \"symlink 2\" ..\n+\telse\n+\t\ttest_write_lines \"symlink 3\" ../\n+\tfi >expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n-\techo HEAD: | git cat-file --batch-check >expect &&\n-\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n-\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n+\tif test_have_prereq !MINGW\n+\tthen\n+\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n+\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n+\t\t# different shape than Git expects them.\n+\t\techo HEAD: | git cat-file --batch-check >expect &&\n+\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual\n+\tfi &&\n \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp found actual &&\n \techo symlink 7 >expect &&\n-- \ngitgitgadget\n\n"},{"id":"531444","messageId":"930828c6936c526a91059dda40960508bc6b80f0.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 08/10] t1305: skip symlink tests that do not apply to Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:24Z","receivedAt":"2025-11-29T18:28:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn Git for Windows, the gitdir is canonicalized so that even when the\ngitdir is specified via a symbolic link, the `gitdir:` conditional\ninclude will only match the real directory path.\n\nUnfortunately, t1305 codifies a different behavior in two test cases,\nwhich are hereby skipped on Windows.\n\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 8ff2b0c232..6e51f892f3 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '\n \tln -s foo bar &&\n \t(\n \t\tcd bar &&\n@@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '\n \t(\n \t\tcd bar &&\n \t\techo \"[includeIf \\\"gitdir/i:BAR/\\\"]path=bar8\" >>.git/config &&\n-- \ngitgitgadget\n\n"},{"id":"531445","messageId":"b622ff822c367f20ea2c13fea7f404ea2c01f452.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 09/10] t6423: introduce Windows-specific handling for symlinking to /dev/null","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:25Z","receivedAt":"2025-11-29T18:28:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe device `/dev/null` does not exist on Windows, it's called `NUL`\nthere. Calling `ln -s /dev/null my-symlink` in a symlink-enabled MSYS2\nBash will therefore literally link to a file or directory called `null`\nthat is supposed to be in the current drive's top-level `dev` directory.\nWhich typically does not exist.\n\nThe test, however, really wants the created symbolic link to point to\nthe NUL device. Let's instead use the `mklink` utility on Windows to\nperform that job, and keep using `ln -s /dev/null <target>` on\nnon-Windows platforms.\n\nWhile at it, add the missing `SYMLINKS` prereq because this test _still_\nwould not pass on Windows before support for symbolic links is\nupstreamed from Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6423-merge-rename-directories.sh | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex 533ac85dc8..53535a8ebf 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -5158,13 +5158,18 @@ test_setup_12m () {\n \t\tgit switch B &&\n \t\tgit rm dir/subdir/file &&\n \t\tmkdir dir &&\n-\t\tln -s /dev/null dir/subdir &&\n+\t\tif test_have_prereq MINGW\n+\t\tthen\n+\t\t\tcmd //c 'mklink dir\\subdir NUL'\n+\t\telse\n+\t\t\tln -s /dev/null dir/subdir\n+\t\tfi &&\n \t\tgit add . &&\n \t\tgit commit -m \"B\"\n \t)\n }\n \n-test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\n-- \ngitgitgadget\n\n"},{"id":"531446","messageId":"f7f1e91cef81068f3572b745aebc33d1d2a26c06.1764440906.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-11-29T18:28:26Z","receivedAt":"2025-11-29T18:28:44Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nGit's test suite's relies on Unix shell scripting, which is\nunderstandable, of course, given Git's firm roots (and indeed, ongoing\nfocus) on Linux.\n\nThis fact, combined with Unix shell scripting's natural\nhabitat -- which is, naturally... *drumroll*... Unix --\noften has unintended side effects, where developers expect the test\nsuite to run in a Unix environment, which is an incorrect assumption.\n\nOne instance of this problem can be observed in the 'difftool --dir-diff\nhandles modified symlinks' test case in `t7800-difftool.sh`, which\nassumes that that all absolute paths start with a forward slash. That\nassumption is incorrect in general, e.g. on Windows, where absolute\npaths have many shapes and forms, none of which starts with a forward\nslash.\n\nThe only saving grace is that this test case is currently not run on\nWindows because of the `SYMLINK` prerequisite. However, I am currently\nworking towards upstreaming symbolic link support from Git for Windows\nto upstream Git, which will put a crack into that saving grace.\n\nLet's change that test case so that it does not rely on absolute paths\n(which are passed to the \"external command\" `ls` as parameters and are\ntherefore part of its output, and which the test case wants to filter\nout before verifying that the output is as expected) starting with a\nforward slash. Let's instead rely on the much more reliable fact that\n`ls` will output the path in a line that ends in a colon, and simply\nfilter out those lines by matching said colon instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7800-difftool.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex 9b74db5563..bf0f67378d 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \t\tc\n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \t# The left side contains symlink \"c\" that points to \"b\"\n@@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual\n '\n \n-- \ngitgitgadget\n"},{"id":"531457","messageId":"xmqqms44cb7p.fsf@gitster.g","threadId":"64552","inReplyTo":"3be9594e80c37b2b393f5883a173694ab6793813.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-11-30T05:59:22Z","receivedAt":"2025-11-30T05:59:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> The test case 're-init to move gitdir symlink' wants to compare the\n> contents of `newdir/.git`, which is a symbolic link pointing to a file.\n> However, `git diff --no-index`, which is used by `test_cmp` on Windows,\n> does not resolve symlinks; It shows the symlink _target_ instead (with a\n> file mode of 120000). That is totally unexpected by the test case, which\n> as a consequence fails, meaning that it's a bug in the test case itself.\n\nIt is dubious if it is a bug in this particular test case, or\ntest_cmp implementation that uses \"git diff --no-index\", though.\n\nEither way, when test_cmp here does not do \"diff\", the test would\nfail, so you are correct to notice that this piece of code needs to\nbe patched in some way.  I do not think not comparing is the right\nsolution, though.  Would there be a better option than completely\npunting on the comparison?  Something silly like:\n\n> +\tcase \"$GIT_TEST_CMP\" in\n> +\t# git diff --no-index does not resolve symlinks\n> +\t*--no-index*) cmp expected newdir/.git ;;\n> +\t*) test_cmp expected newdir/.git ;;\n> +\tesac &&\n\nperhaps?\n\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  t/t0001-init.sh | 5 ++++-\n>  1 file changed, 4 insertions(+), 1 deletion(-)\n>\n> diff --git a/t/t0001-init.sh b/t/t0001-init.sh\n> index 618da080dc..2f38e09b58 100755\n> --- a/t/t0001-init.sh\n> +++ b/t/t0001-init.sh\n> @@ -425,7 +425,10 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n>  \tgit init --separate-git-dir ../realgitdir\n>  \t) &&\n>  \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n> -\ttest_cmp expected newdir/.git &&\n> +\tcase \"$GIT_TEST_CMP\" in\n> +\t*--no-index*) ;; # git diff --no-index does not resolve symlinks\n> +\t*) test_cmp expected newdir/.git;;\n> +\tesac &&\n>  \ttest_cmp expected newdir/here &&\n>  \ttest_path_is_dir realgitdir/refs\n>  '\n"},{"id":"531458","messageId":"xmqqikescar1.fsf@gitster.g","threadId":"64552","inReplyTo":"c59a5f24789cff55819caf92d828256f2291b3ff.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-11-30T06:09:22Z","receivedAt":"2025-11-30T06:09:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> Just like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n> 2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\n> suite because that would fail on Windows (because Windows has a much\n> more powerful permission system that cannot be mapped into the simpler\n> user/group/other read/write/execute model).\n\nBut in this case, we are emulating \"mkdir -m 700\" that is expressed\nin a very simpler world view of ugo=rwx with a much more powerful\npermission system, isn't it?  If something is more powerful, it\nshould be easy/possible to emulate a simpler system, I would naively\nthink.\n\nIn any case, a more productive than rethinking the \"can we express\nwhat mkdir -m <mode>, which is a construct in a simpler world, wants\nto do in terms of a much more powerful permission system?\" would be\nto see if the test linter can be taught about this particular rule.\n\nIt is easy to forget that there is a platform we care about whose\ntesting environment that emulates POSIX does not like \"mkdir -m\n700\", and it is a bit too much to burden developers to remember.\n\n> There was one forgotten instance of this which was hidden by a `SYMLINK`\n> prerequisite. Currently, this prevents this test case from being\n> executed on Windows, but with the upcoming support for symbolic links,\n> it would become a problem.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  t/t0301-credential-cache.sh | 3 ++-\n>  1 file changed, 2 insertions(+), 1 deletion(-)\n>\n> diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\n> index dc30289f75..6f7cfd9e33 100755\n> --- a/t/t0301-credential-cache.sh\n> +++ b/t/t0301-credential-cache.sh\n> @@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n>  \t\trmdir \\\"\\$HOME/dir/\\\" &&\n>  \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n>  \t\" &&\n> -\tmkdir -p -m 700 \"$HOME/dir/\" &&\n> +\tmkdir -p \"$HOME/dir/\" &&\n> +\tchmod 700 \"$HOME/dir/\" &&\n\nThat \"mkdir -p -m 700\" is a no-no while \"mkdir -p\" followed by\n\"chmod 700\" is OK is a bit puzzling, but I assume $HOME does exist\nin the testing envioronment, so this new sequence should be\nequivalent in the simpler permission system.  If it works fine on\nWindows, that is great.\n\n>  \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n>  \tcheck approve cache <<-\\EOF &&\n>  \tprotocol=https\n"},{"id":"531459","messageId":"xmqqecpgc8wd.fsf@gitster.g","threadId":"64552","inReplyTo":"96e279f50ebc26084095e781cf58db233fa05b74.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-11-30T06:49:22Z","receivedAt":"2025-11-30T06:49:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> The `_wopen()` function would gladly follow a symbolic link to a\n> non-existent file and create it when given above-mentioned flags.\n>\n> Git expects the `open()` call to fail, though. So let's add yet another\n> work-around to pretend that Windows behaves like Linux.\n\n\"like Linux\" -> \"as POSIX expects\"?\n\ncf. https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n\n> This is required to let t4115.8(--reject removes .rej symlink if it\n> exists) pass on Windows when enabling the MSYS2 runtime's symbolic link\n> support.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  compat/mingw.c | 14 ++++++++++++++\n>  1 file changed, 14 insertions(+)\n>\n> diff --git a/compat/mingw.c b/compat/mingw.c\n> index 736a07a028..9fbf12a3d3 100644\n> --- a/compat/mingw.c\n> +++ b/compat/mingw.c\n> @@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n>  \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n>  \twchar_t wfilename[MAX_PATH];\n>  \topen_fn_t open_fn;\n> +\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n>  \n>  \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n>  \n> @@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n>  \telse if (xutftowcs_path(wfilename, filename) < 0)\n>  \t\treturn -1;\n>  \n> +\t/*\n> +\t * When `symlink` exists and is a symbolic link pointing to a\n> +\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n> +\t * create that file. Not what we want: Linux would say `EEXIST`\n> +\t * in that instance, which is therefore what Git expects.\n> +\t */\n\n\"Linux\" -> \"open() on POSIX-compliant systems\".\n\nIOW, _wopen() does not have to behave like POSIX open() and the compat/\nlayer is how the emulation goes.\n\nFWIW, this is not limited to symbolic links but anything that exists\nat the path specified should cause the same EEXIST failure.  The\nO_CREAT|O_EXCL combination asks the system to atomically create the\nthing anew (or fail).\n\n    O_EXCL\n        If O_CREAT and O_EXCL are set, open() shall fail if the file\n        exists. The check for the existence of the file and the creation of\n        the file if it does not exist shall be atomic with respect to other\n        threads executing open() naming the same filename in the same\n        directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are\n        set, and path names a symbolic link, open() shall fail and set errno\n        to [EEXIST], regardless of the contents of the symbolic link. If\n        O_EXCL is set and O_CREAT is not set, the result is undefined.\n\n> +\tif (create &&\n> +\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n> +\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n> +\t\terrno = EEXIST;\n> +\t\treturn -1;\n> +\t}\n> +\n>  \tfd = open_fn(wfilename, oflags, mode);\n>  \n>  \t/*\n"},{"id":"531460","messageId":"xmqqa504c8wa.fsf@gitster.g","threadId":"64552","inReplyTo":"f7f1e91cef81068f3572b745aebc33d1d2a26c06.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-11-30T06:49:25Z","receivedAt":"2025-11-30T06:49:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>\n> Git's test suite's relies on Unix shell scripting, which is\n> understandable, of course, given Git's firm roots (and indeed, ongoing\n> focus) on Linux.\n>\n> This fact, combined with Unix shell scripting's natural\n> habitat -- which is, naturally... *drumroll*... Unix --\n> often has unintended side effects, where developers expect the test\n> suite to run in a Unix environment, which is an incorrect assumption.\n\nSurely, those who are primarily on Linux, or those whose background\nis from other kinds of UNIX, cannot be expected to be intimately\nfamiliar with how the POSIX shell script environment ported to\nWindows platform behaves, and it is understandable if they expect,\nas a port, it would behave more or less the same way as they are\naccustomed to on UNIX.  Even though POSIX shell script environment\nused to run our end-to-end tests are ported to Windows, however, the\nscripts still need to be aware of certain things that have to be\ndone differently in Windows environment from how they are done in\nUNIX environment.  Here what you fixed, the absolute pathname may\nbegin with <drive> <colon> instead of <slash>, may be one of them.\n\nAnd these differences are not necessarily well known and/or\nadvertised to many of the developers who have written our tests on\nLinux or macOS over time.  I wonder if we can do something about\nthat, instead of reacting to breakage retroactively while\ncomplaining with disgust about the platform differences, which is\nwhat we often have to see on this list.\n\n> Let's instead rely on the much more reliable fact that\n> `ls` will output the path in a line that ends in a colon, and simply\n> filter out those lines by matching said colon instead.\n\nThat is clever and clean, a very well crafted solution.\n\nWill queue.  The entire series looked quite sensibly reasoned.\n\nThanks.\n"},{"id":"531461","messageId":"CAPig+cSKmmSewLYp_zAk7y+y=STxPjvG9f5LzrmTbtvNt_AoPw@mail.gmail.com","threadId":"64552","inReplyTo":"f7f1e91cef81068f3572b745aebc33d1d2a26c06.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2025-11-30T06:57:48Z","receivedAt":"2025-11-30T06:58:00Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Sat, Nov 29, 2025 at 1:29 PM Johannes Schindelin via GitGitGadget\n<gitgitgadget@gmail.com> wrote:\n> Git's test suite's relies on Unix shell scripting, which is\n> understandable, of course, given Git's firm roots (and indeed, ongoing\n> focus) on Linux.\n>\n> This fact, combined with Unix shell scripting's natural\n> habitat -- which is, naturally... *drumroll*... Unix --\n> often has unintended side effects, where developers expect the test\n> suite to run in a Unix environment, which is an incorrect assumption.\n>\n> One instance of this problem can be observed in the 'difftool --dir-diff\n> handles modified symlinks' test case in `t7800-difftool.sh`, which\n> assumes that that all absolute paths start with a forward slash. That\n\ns/that that/that/\n\n> assumption is incorrect in general, e.g. on Windows, where absolute\n> paths have many shapes and forms, none of which starts with a forward\n> slash.\n>\n> The only saving grace is that this test case is currently not run on\n> Windows because of the `SYMLINK` prerequisite. However, I am currently\n> working towards upstreaming symbolic link support from Git for Windows\n> to upstream Git, which will put a crack into that saving grace.\n>\n> Let's change that test case so that it does not rely on absolute paths\n> (which are passed to the \"external command\" `ls` as parameters and are\n> therefore part of its output, and which the test case wants to filter\n> out before verifying that the output is as expected) starting with a\n> forward slash. Let's instead rely on the much more reliable fact that\n> `ls` will output the path in a line that ends in a colon, and simply\n> filter out those lines by matching said colon instead.\n>\n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n"},{"id":"531492","messageId":"aS1kEb2dvLU-7FnM@pks.im","threadId":"64552","inReplyTo":"0866db0a17d88016617e7e626dc032af599679c8.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 06/10] t0600: fix incomplete prerequisite for a test case","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-12-01T09:46:57Z","receivedAt":"2025-12-01T09:47:04Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Sat, Nov 29, 2025 at 06:28:22PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n> The 'symref transaction supports symlinks' test case is guarded by the\n> `SYMLINK` prerequisite because `core.prefersymlinkrefs = true` requires\n> symbolic links to be supported.\n> \n> However, the `preferSymlinkRefs` feature is not supported on Windows,\n> therefore this test case needs the `MINGW` prerequisite, too.\n> \n> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> ---\n>  t/t0600-reffiles-backend.sh | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n> \n> diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\n> index b11126ed47..74bfa2e9ba 100755\n> --- a/t/t0600-reffiles-backend.sh\n> +++ b/t/t0600-reffiles-backend.sh\n> @@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '\n>  \tesac\n>  '\n>  \n> -test_expect_success SYMLINKS 'symref transaction supports symlinks' '\n> +test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '\n>  \ttest_when_finished \"git symbolic-ref -d TEST_SYMREF_HEAD\" &&\n>  \tgit update-ref refs/heads/new @ &&\n>  \ttest_config core.prefersymlinkrefs true &&\n\nMakes sense. There's a couple more cases where we set this config key:\n\n  - In a subsequent test in t0600, but there we explicitly set it to\n    \"false\". So this would naturally be supported by Windows.\n\n  - In t7201 we set the value to \"yes\", but we never verify that the\n    written reference is a symbolic link in the first place. I guess\n    that we could rather remove setting the configuration value here, as\n    we are about to deprecate support for symrefs via symbolic links in\n    the first place. But that's certainly outside of the scope of this\n    series.\n\n  - In t9903 we do the same, but likewise, we don't check whether the\n    written file is a symbolic link.\n\nSo yes, this seems to be the only instance where we actually need to\nadapt tests.\n\nThanks!\n\nPatrick\n"},{"id":"531493","messageId":"aS1kI0AR8TLVkm07@pks.im","threadId":"64552","inReplyTo":"8a7c68b629f64a3fd8c08f54b5e8693f6568885c.1764440906.git.gitgitgadget@gmail.com","subject":"Re: [PATCH 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-12-01T09:47:15Z","receivedAt":"2025-12-01T09:47:21Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Sat, Nov 29, 2025 at 06:28:23PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\n> index 1f61b666a7..0eee3bb878 100755\n> --- a/t/t1006-cat-file.sh\n> +++ b/t/t1006-cat-file.sh\n> @@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-\n>  \techo .. >>expect &&\n>  \techo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&\n>  \ttest_cmp expect actual &&\n> -\techo symlink 3 >expect &&\n> -\techo ../ >>expect &&\n> +\tif test_have_prereq MINGW,SYMLINKS\n> +\tthen\n> +\t\ttest_write_lines \"symlink 2\" ..\n> +\telse\n> +\t\ttest_write_lines \"symlink 3\" ../\n> +\tfi >expect &&\n>  \techo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n>  \ttest_cmp expect actual\n>  '\n\nOkay.\n\n>  test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n> -\techo HEAD: | git cat-file --batch-check >expect &&\n> -\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> -\ttest_cmp expect actual &&\n> -\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> -\ttest_cmp expect actual &&\n> +\tif test_have_prereq !MINGW\n> +\tthen\n> +\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n> +\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n> +\t\t# different shape than Git expects them.\n> +\t\techo HEAD: | git cat-file --batch-check >expect &&\n> +\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> +\t\ttest_cmp expect actual &&\n> +\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> +\t\ttest_cmp expect actual\n> +\tfi &&\n>  \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n>  \ttest_cmp found actual &&\n>  \techo symlink 7 >expect &&\n\nI'm not quite sure I follow, so my questions may be dumb. Does this mean\nthat git-cat-file(1) fails to follow the symlink in this case, and\nconsequently we cannot execute it at all? If so, is this a bug that\nwe'll eventually have to fix?\n\nIf this is something we can fix it could be sensible to have an `else`\nbranch that documents the failure case. In that case, we would then\nnotice that the test fails once we fix the underlying issue.\n\nPatrick\n"},{"id":"531507","messageId":"4cf1c638-3b0b-a36a-ce35-41d55e9fae12@gmx.de","threadId":"64552","inReplyTo":"xmqqecpgc8wd.fsf@gitster.g","subject":"Re: [PATCH 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:18:17Z","receivedAt":"2025-12-01T13:18:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 29 Nov 2025, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n> \n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > The `_wopen()` function would gladly follow a symbolic link to a\n> > non-existent file and create it when given above-mentioned flags.\n> >\n> > Git expects the `open()` call to fail, though. So let's add yet another\n> > work-around to pretend that Windows behaves like Linux.\n> \n> \"like Linux\" -> \"as POSIX expects\"?\n> \n> cf. https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n\nYou are both correct and incorrect. The behavior I described indeed is not\nlimited to Linux, insofar you are correct. The behavior I wanted to\nimitate is Linux', though, not POSIX.\n\nI noticed that there was a recent shift, mostly by one particular\ncontributor on this list, who pushes for POSIX compliance to be the gold\nstandard Git lives by. However, that does not match my understanding of\nwhat the Git project agreed upon, as documented in\nhttps://gitlab.com/git-scm/git/-/blob/v2.52.0/Documentation/CodingGuidelines?ref_type=tags#L4-6\n(and there was no attempt to change this).\n\nAs such, I still deem it more appropriate to keep the commit message as I\nwrote it, as it matches my intent.\n\nYou're of course free to edit the commit message to your liking, as you\nhave done in the past. It just would not match my intent anymore.\n\nCiao,\nJohannes\n\n> > This is required to let t4115.8(--reject removes .rej symlink if it\n> > exists) pass on Windows when enabling the MSYS2 runtime's symbolic link\n> > support.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  compat/mingw.c | 14 ++++++++++++++\n> >  1 file changed, 14 insertions(+)\n> >\n> > diff --git a/compat/mingw.c b/compat/mingw.c\n> > index 736a07a028..9fbf12a3d3 100644\n> > --- a/compat/mingw.c\n> > +++ b/compat/mingw.c\n> > @@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n> >  \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n> >  \twchar_t wfilename[MAX_PATH];\n> >  \topen_fn_t open_fn;\n> > +\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n> >  \n> >  \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n> >  \n> > @@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n> >  \telse if (xutftowcs_path(wfilename, filename) < 0)\n> >  \t\treturn -1;\n> >  \n> > +\t/*\n> > +\t * When `symlink` exists and is a symbolic link pointing to a\n> > +\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n> > +\t * create that file. Not what we want: Linux would say `EEXIST`\n> > +\t * in that instance, which is therefore what Git expects.\n> > +\t */\n> \n> \"Linux\" -> \"open() on POSIX-compliant systems\".\n> \n> IOW, _wopen() does not have to behave like POSIX open() and the compat/\n> layer is how the emulation goes.\n> \n> FWIW, this is not limited to symbolic links but anything that exists\n> at the path specified should cause the same EEXIST failure.  The\n> O_CREAT|O_EXCL combination asks the system to atomically create the\n> thing anew (or fail).\n> \n>     O_EXCL\n>         If O_CREAT and O_EXCL are set, open() shall fail if the file\n>         exists. The check for the existence of the file and the creation of\n>         the file if it does not exist shall be atomic with respect to other\n>         threads executing open() naming the same filename in the same\n>         directory with O_EXCL and O_CREAT set. If O_EXCL and O_CREAT are\n>         set, and path names a symbolic link, open() shall fail and set errno\n>         to [EEXIST], regardless of the contents of the symbolic link. If\n>         O_EXCL is set and O_CREAT is not set, the result is undefined.\n> \n> > +\tif (create &&\n> > +\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n> > +\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n> > +\t\terrno = EEXIST;\n> > +\t\treturn -1;\n> > +\t}\n> > +\n> >  \tfd = open_fn(wfilename, oflags, mode);\n> >  \n> >  \t/*\n> \n"},{"id":"531509","messageId":"07dd2e66-7cdc-7839-aaf7-274b116df51c@gmx.de","threadId":"64552","inReplyTo":"xmqqms44cb7p.fsf@gitster.g","subject":"Re: [PATCH 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:20:28Z","receivedAt":"2025-12-01T13:20:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 29 Nov 2025, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n> \n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > The test case 're-init to move gitdir symlink' wants to compare the\n> > contents of `newdir/.git`, which is a symbolic link pointing to a file.\n> > However, `git diff --no-index`, which is used by `test_cmp` on Windows,\n> > does not resolve symlinks; It shows the symlink _target_ instead (with a\n> > file mode of 120000). That is totally unexpected by the test case, which\n> > as a consequence fails, meaning that it's a bug in the test case itself.\n> \n> It is dubious if it is a bug in this particular test case, or\n> test_cmp implementation that uses \"git diff --no-index\", though.\n> \n> Either way, when test_cmp here does not do \"diff\", the test would\n> fail, so you are correct to notice that this piece of code needs to\n> be patched in some way.  I do not think not comparing is the right\n> solution, though.  Would there be a better option than completely\n> punting on the comparison?  Something silly like:\n> \n> > +\tcase \"$GIT_TEST_CMP\" in\n> > +\t# git diff --no-index does not resolve symlinks\n> > +\t*--no-index*) cmp expected newdir/.git ;;\n> > +\t*) test_cmp expected newdir/.git ;;\n> > +\tesac &&\n> \n> perhaps?\n\nSure. It's not like this adds much confidence, though, as the tested-for\nfunctionality isn't specific to Windows, so I'd expect this to fail on\nLinux, too, if it was broken, and running that comparison on Windows does\nnot add much.\n\nSince you spent time on this, I will change it, though.\n\nCiao,\nJohannes\n\n> \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  t/t0001-init.sh | 5 ++++-\n> >  1 file changed, 4 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/t/t0001-init.sh b/t/t0001-init.sh\n> > index 618da080dc..2f38e09b58 100755\n> > --- a/t/t0001-init.sh\n> > +++ b/t/t0001-init.sh\n> > @@ -425,7 +425,10 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n> >  \tgit init --separate-git-dir ../realgitdir\n> >  \t) &&\n> >  \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n> > -\ttest_cmp expected newdir/.git &&\n> > +\tcase \"$GIT_TEST_CMP\" in\n> > +\t*--no-index*) ;; # git diff --no-index does not resolve symlinks\n> > +\t*) test_cmp expected newdir/.git;;\n> > +\tesac &&\n> >  \ttest_cmp expected newdir/here &&\n> >  \ttest_path_is_dir realgitdir/refs\n> >  '\n> \n"},{"id":"531510","messageId":"e355d80a-a0e9-7795-06cd-1b8acfa6c7c8@gmx.de","threadId":"64552","inReplyTo":"xmqqikescar1.fsf@gitster.g","subject":"Re: [PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:25:40Z","receivedAt":"2025-12-01T13:25:46Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Sat, 29 Nov 2025, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n> \n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >\n> > Just like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n> > 2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\n> > suite because that would fail on Windows (because Windows has a much\n> > more powerful permission system that cannot be mapped into the simpler\n> > user/group/other read/write/execute model).\n> \n> But in this case, we are emulating \"mkdir -m 700\" that is expressed\n> in a very simpler world view of ugo=rwx with a much more powerful\n> permission system, isn't it?  If something is more powerful, it\n> should be easy/possible to emulate a simpler system, I would naively\n> think.\n\nIt is probably outside the purview of this patch series to question why\nCygwin's `mkdir -m` doesn't emulate Unix semantics let alone to fix it. So\nI'll bow out of that tangent.\n\n> In any case, a more productive than rethinking the \"can we express\n> what mkdir -m <mode>, which is a construct in a simpler world, wants\n> to do in terms of a much more powerful permission system?\" would be\n> to see if the test linter can be taught about this particular rule.\n\nSeeing that this issue had to be fixed twice within the course of over 4\nyears, https://xkcd.com/1205/ applies.\n\nCiao,\nJohannes\n\n> \n> It is easy to forget that there is a platform we care about whose\n> testing environment that emulates POSIX does not like \"mkdir -m\n> 700\", and it is a bit too much to burden developers to remember.\n> \n> > There was one forgotten instance of this which was hidden by a `SYMLINK`\n> > prerequisite. Currently, this prevents this test case from being\n> > executed on Windows, but with the upcoming support for symbolic links,\n> > it would become a problem.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  t/t0301-credential-cache.sh | 3 ++-\n> >  1 file changed, 2 insertions(+), 1 deletion(-)\n> >\n> > diff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\n> > index dc30289f75..6f7cfd9e33 100755\n> > --- a/t/t0301-credential-cache.sh\n> > +++ b/t/t0301-credential-cache.sh\n> > @@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n> >  \t\trmdir \\\"\\$HOME/dir/\\\" &&\n> >  \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n> >  \t\" &&\n> > -\tmkdir -p -m 700 \"$HOME/dir/\" &&\n> > +\tmkdir -p \"$HOME/dir/\" &&\n> > +\tchmod 700 \"$HOME/dir/\" &&\n> \n> That \"mkdir -p -m 700\" is a no-no while \"mkdir -p\" followed by\n> \"chmod 700\" is OK is a bit puzzling, but I assume $HOME does exist\n> in the testing envioronment, so this new sequence should be\n> equivalent in the simpler permission system.  If it works fine on\n> Windows, that is great.\n> \n> >  \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n> >  \tcheck approve cache <<-\\EOF &&\n> >  \tprotocol=https\n> \n"},{"id":"531512","messageId":"70fe338c-8802-324f-ca5a-d3ba369ea661@gmx.de","threadId":"64552","inReplyTo":"aS1kEb2dvLU-7FnM@pks.im","subject":"Re: [PATCH 06/10] t0600: fix incomplete prerequisite for a test case","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:27:35Z","receivedAt":"2025-12-01T13:27:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Mon, 1 Dec 2025, Patrick Steinhardt wrote:\n\n> On Sat, Nov 29, 2025 at 06:28:22PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > \n> > The 'symref transaction supports symlinks' test case is guarded by the\n> > `SYMLINK` prerequisite because `core.prefersymlinkrefs = true` requires\n> > symbolic links to be supported.\n> > \n> > However, the `preferSymlinkRefs` feature is not supported on Windows,\n> > therefore this test case needs the `MINGW` prerequisite, too.\n> > \n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> > ---\n> >  t/t0600-reffiles-backend.sh | 2 +-\n> >  1 file changed, 1 insertion(+), 1 deletion(-)\n> > \n> > diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\n> > index b11126ed47..74bfa2e9ba 100755\n> > --- a/t/t0600-reffiles-backend.sh\n> > +++ b/t/t0600-reffiles-backend.sh\n> > @@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '\n> >  \tesac\n> >  '\n> >  \n> > -test_expect_success SYMLINKS 'symref transaction supports symlinks' '\n> > +test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '\n> >  \ttest_when_finished \"git symbolic-ref -d TEST_SYMREF_HEAD\" &&\n> >  \tgit update-ref refs/heads/new @ &&\n> >  \ttest_config core.prefersymlinkrefs true &&\n> \n> Makes sense. There's a couple more cases where we set this config key:\n> \n>   - In a subsequent test in t0600, but there we explicitly set it to\n>     \"false\". So this would naturally be supported by Windows.\n> \n>   - In t7201 we set the value to \"yes\", but we never verify that the\n>     written reference is a symbolic link in the first place. I guess\n>     that we could rather remove setting the configuration value here, as\n>     we are about to deprecate support for symrefs via symbolic links in\n>     the first place. But that's certainly outside of the scope of this\n>     series.\n> \n>   - In t9903 we do the same, but likewise, we don't check whether the\n>     written file is a symbolic link.\n> \n> So yes, this seems to be the only instance where we actually need to\n> adapt tests.\n\nThank you for doing my homework. I meant to jot it down in my TODO list as\nsomething that I needed to check before sending the series, but I forgot\nto jot it down and therefore forgot.\n\nThanks again!\nJohannes\n"},{"id":"531514","messageId":"fff2c7d2-acfd-7052-5e7a-e617bdd1d2e6@gmx.de","threadId":"64552","inReplyTo":"aS1kI0AR8TLVkm07@pks.im","subject":"Re: [PATCH 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:29:45Z","receivedAt":"2025-12-01T13:29:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Patrick,\n\nOn Mon, 1 Dec 2025, Patrick Steinhardt wrote:\n\n> On Sat, Nov 29, 2025 at 06:28:23PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> \n> >  test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n> > -\techo HEAD: | git cat-file --batch-check >expect &&\n> > -\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> > -\ttest_cmp expect actual &&\n> > -\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> > -\ttest_cmp expect actual &&\n> > +\tif test_have_prereq !MINGW\n> > +\tthen\n> > +\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n> > +\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n> > +\t\t# different shape than Git expects them.\n> > +\t\techo HEAD: | git cat-file --batch-check >expect &&\n> > +\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> > +\t\ttest_cmp expect actual &&\n> > +\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> > +\t\ttest_cmp expect actual\n> > +\tfi &&\n> >  \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n> >  \ttest_cmp found actual &&\n> >  \techo symlink 7 >expect &&\n> \n> I'm not quite sure I follow, so my questions may be dumb. Does this mean\n> that git-cat-file(1) fails to follow the symlink in this case, and\n> consequently we cannot execute it at all? If so, is this a bug that\n> we'll eventually have to fix?\n\nNo, it means that the symbolic links are not even created in the way Git's\ntest suite thinks they are (or should be) created. The way those symbolic\nlink targets exist on disk (i.e. the way Cygwin's\n`winsymlinks:nativestrict` mode constructs them), the expectations of this\ntest cannot be met, no matter what `cat-file` does.\n\nCiao,\nJohannes\n"},{"id":"531515","messageId":"3000e017-189d-e8ea-83da-5bccfd595349@gmx.de","threadId":"64552","inReplyTo":"CAPig+cSKmmSewLYp_zAk7y+y=STxPjvG9f5LzrmTbtvNt_AoPw@mail.gmail.com","subject":"Re: [PATCH 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-01T13:30:53Z","receivedAt":"2025-12-01T13:30:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Eric,\n\nOn Sun, 30 Nov 2025, Eric Sunshine wrote:\n\n> On Sat, Nov 29, 2025 at 1:29 PM Johannes Schindelin via GitGitGadget\n> <gitgitgadget@gmail.com> wrote:\n> > Git's test suite's relies on Unix shell scripting, which is\n> > understandable, of course, given Git's firm roots (and indeed, ongoing\n> > focus) on Linux.\n> >\n> > This fact, combined with Unix shell scripting's natural\n> > habitat -- which is, naturally... *drumroll*... Unix --\n> > often has unintended side effects, where developers expect the test\n> > suite to run in a Unix environment, which is an incorrect assumption.\n> >\n> > One instance of this problem can be observed in the 'difftool --dir-diff\n> > handles modified symlinks' test case in `t7800-difftool.sh`, which\n> > assumes that that all absolute paths start with a forward slash. That\n> \n> s/that that/that/\n\nThanks,\nJohannes\n\n> \n> > assumption is incorrect in general, e.g. on Windows, where absolute\n> > paths have many shapes and forms, none of which starts with a forward\n> > slash.\n> >\n> > The only saving grace is that this test case is currently not run on\n> > Windows because of the `SYMLINK` prerequisite. However, I am currently\n> > working towards upstreaming symbolic link support from Git for Windows\n> > to upstream Git, which will put a crack into that saving grace.\n> >\n> > Let's change that test case so that it does not rely on absolute paths\n> > (which are passed to the \"external command\" `ls` as parameters and are\n> > therefore part of its output, and which the test case wants to filter\n> > out before verifying that the output is as expected) starting with a\n> > forward slash. Let's instead rely on the much more reliable fact that\n> > `ls` will output the path in a line that ends in a colon, and simply\n> > filter out those lines by matching said colon instead.\n> >\n> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> \n"},{"id":"531516","messageId":"aS2ZUVfTf9XWCfI4@pks.im","threadId":"64552","inReplyTo":"fff2c7d2-acfd-7052-5e7a-e617bdd1d2e6@gmx.de","subject":"Re: [PATCH 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-12-01T13:34:09Z","receivedAt":"2025-12-01T13:34:15Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Dec 01, 2025 at 02:29:45PM +0100, Johannes Schindelin wrote:\n> Hi Patrick,\n> \n> On Mon, 1 Dec 2025, Patrick Steinhardt wrote:\n> \n> > On Sat, Nov 29, 2025 at 06:28:23PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> > \n> > >  test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n> > > -\techo HEAD: | git cat-file --batch-check >expect &&\n> > > -\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> > > -\ttest_cmp expect actual &&\n> > > -\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> > > -\ttest_cmp expect actual &&\n> > > +\tif test_have_prereq !MINGW\n> > > +\tthen\n> > > +\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n> > > +\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n> > > +\t\t# different shape than Git expects them.\n> > > +\t\techo HEAD: | git cat-file --batch-check >expect &&\n> > > +\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n> > > +\t\ttest_cmp expect actual &&\n> > > +\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n> > > +\t\ttest_cmp expect actual\n> > > +\tfi &&\n> > >  \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n> > >  \ttest_cmp found actual &&\n> > >  \techo symlink 7 >expect &&\n> > \n> > I'm not quite sure I follow, so my questions may be dumb. Does this mean\n> > that git-cat-file(1) fails to follow the symlink in this case, and\n> > consequently we cannot execute it at all? If so, is this a bug that\n> > we'll eventually have to fix?\n> \n> No, it means that the symbolic links are not even created in the way Git's\n> test suite thinks they are (or should be) created. The way those symbolic\n> link targets exist on disk (i.e. the way Cygwin's\n> `winsymlinks:nativestrict` mode constructs them), the expectations of this\n> test cannot be met, no matter what `cat-file` does.\n\nAh, makes sense. Thanks for clarifying!\n\nPatrick\n"},{"id":"531541","messageId":"xmqqfr9t8flg.fsf@gitster.g","threadId":"64552","inReplyTo":"e355d80a-a0e9-7795-06cd-1b8acfa6c7c8@gmx.de","subject":"Re: [PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-02T08:15:07Z","receivedAt":"2025-12-02T08:15:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> In any case, a more productive than rethinking the \"can we express\n>> what mkdir -m <mode>, which is a construct in a simpler world, wants\n>> to do in terms of a much more powerful permission system?\" would be\n>> to see if the test linter can be taught about this particular rule.\n>\n> Seeing that this issue had to be fixed twice within the course of over 4\n> years, https://xkcd.com/1205/ applies.\n\nIt means that we are punting and are not proactively helping future\ndevelopers who may make the same mistake, but we expect it would be\nrather rare so I am OK with us making that trade-off.  But then can\nyou dial back your condescending tone against those who are not as\nfamiliar as glitches in the Windows port of POSIX shell environment\nwe use for tests?\n\nThanks.\n\n>> It is easy to forget that there is a platform we care about whose\n>> testing environment that emulates POSIX does not like \"mkdir -m\n>> 700\", and it is a bit too much to burden developers to remember.\n"},{"id":"531542","messageId":"xmqqbjkh8fle.fsf@gitster.g","threadId":"64552","inReplyTo":"07dd2e66-7cdc-7839-aaf7-274b116df51c@gmx.de","subject":"Re: [PATCH 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-02T08:15:09Z","receivedAt":"2025-12-02T08:15:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> > +\tcase \"$GIT_TEST_CMP\" in\n>> > +\t# git diff --no-index does not resolve symlinks\n>> > +\t*--no-index*) cmp expected newdir/.git ;;\n>> > +\t*) test_cmp expected newdir/.git ;;\n>> > +\tesac &&\n>> \n>> perhaps?\n>\n> Sure. It's not like this adds much confidence, though, as the tested-for\n> functionality isn't specific to Windows, so I'd expect this to fail on\n> Linux, too, if it was broken, and running that comparison on Windows does\n> not add much.\n\nIt sounds like you are saying running tests on Windows on most of\nthe platform neutral Git code is waste of resources, and looking at\nthe number of shareded tests used in CI, it might not be a bad idea\nif we can cleanly separate the Git functionality into two categories\n(i.e., those that must behave identically on all platforms and\nothers) and shuffle our tests around to let platforms that runs our\ntests slower only the \"other\" tests, while the faster platform to\nrun all of them.  But I am not sure if that approach is a practical.\n\n> Since you spent time on this, I will change it, though.\n\nThe time I spent does not matter as much as the time other folks\nwill spend scratching their heads reading the code left by this\npatch.  I will be mostly offline this week, so please take your\ntime.\n\nThanks.\n\n"},{"id":"531551","messageId":"8129143e-79fb-cadc-8f88-9c8daa73c317@gmx.de","threadId":"64552","inReplyTo":"xmqqfr9t8flg.fsf@gitster.g","subject":"Re: [PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-02T11:14:09Z","receivedAt":"2025-12-02T11:14:15Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 2 Dec 2025, Junio C Hamano wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n> \n> >> In any case, a more productive than rethinking the \"can we express\n> >> what mkdir -m <mode>, which is a construct in a simpler world, wants\n> >> to do in terms of a much more powerful permission system?\" would be\n> >> to see if the test linter can be taught about this particular rule.\n> >\n> > Seeing that this issue had to be fixed twice within the course of over 4\n> > years, https://xkcd.com/1205/ applies.\n> \n> It means that we are punting and are not proactively helping future\n> developers who may make the same mistake, but we expect it would be\n> rather rare so I am OK with us making that trade-off.\n\nGood, then we're on the same page regarding this approach.\n\n> But then can you dial back your condescending tone against those who are\n> not as familiar as glitches in the Windows port of POSIX shell\n> environment we use for tests?\n\nPlease don't read more into my words than merely a large frustration with\nthe state of Git's test suite. It might be mostly conforming to the 80\ncharacter per line convention, yet I yearn instead for the same speed,\nreadability, portability and debuggability that I've encountered in other\nprojects' test suites.\n\nCiao,\nJohannes\n"},{"id":"531704","messageId":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.git.1764440906.gitgitgadget@gmail.com","subject":"[PATCH v2 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:15Z","receivedAt":"2025-12-05T15:02:31Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git for Windows has supported symbolic links for quite some time: In\nhttps://github.com/git-for-windows/git/pull/156, this support was introduced\nalready into Git for Windows v2.4.2.windows.1 in May 2015.\n\nHowever, the Git for Windows CI never ran the test suite with symbolic link\nsupport because the MSYS2 runtime (i.e. the POSIX emulation layer required\nto run Git's test suite because the latter is written in Unix shell script)\ndoes not support symbolic links right out of the box. This is for historical\nreasons: Symbolic link support was introduced in Windows 7, where these\nlinks could only be created by administrators by default, and it took until\nWindows 10 Build 14972 that at least in Developer Mode, non-administrators\nwould be permitted to create them.\n\nThe MSYS2 runtime does have some sort of support for symbolic links,\nalthough with caveats: seeing as it expects the inputs as Unix-like paths,\nbut the outputs need to be Win32 symbolic links pointing to Win32 paths,\nsome normalization has to be performed in the process. This leads to\nsometimes surprising behavior e.g. when a link target like a/b/.. is\nnormalized to a.\n\nIt has been a minute or three since the time when Windows versions without\nsymbolic link support were common, therefore there are plans to turn on that\nsupport in the MSYS2 runtime on these Windows versions by default, see\nhttps://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n\nTo prepare for this, I am working toward upstreaming Git for Windows' own\nsupport for symbolic links. And to prepare for that, in turn, I am hereby\ncontributing preemptively the fixes required to eventually let Git's test\nsuite pass when both MSYS2 runtime and Git support symbolic links.\n\nAs a bonus, this patch series also contains fixes for the Perl tests (which\nwere broken for a few years, unnoticed because the CI runs need to save on\nruntime and therefore skip the Perl tests because the consume a lot of\ntime).\n\nChanges since v1:\n\n * Fixed a grammar issue.\n * Using cmp rather than skipping the comparison (thanks Junio).\n * Extended a commit message to explain that it covers all the cases where\n   core.preferSymlinkRefs needs special care.\n\nJohannes Schindelin (10):\n  t9700: accommodate for Windows paths\n  apply: symbolic links lack a \"trustable executable bit\"\n  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  t0001: handle `diff --no-index` gracefully\n  t0301: another fix for Windows compatibility\n  t0600: fix incomplete prerequisite for a test case\n  t1006: accommodate for symlink support in MSYS2\n  t1305: skip symlink tests that do not apply to Windows\n  t6423: introduce Windows-specific handling for symlinking to /dev/null\n  t7800: work around the MSYS path conversion on Windows\n\n apply.c                             |  2 +-\n compat/mingw.c                      | 14 ++++++++++++++\n t/t0001-init.sh                     |  6 +++++-\n t/t0301-credential-cache.sh         |  3 ++-\n t/t0600-reffiles-backend.sh         |  2 +-\n t/t1006-cat-file.sh                 | 24 +++++++++++++++++-------\n t/t1305-config-include.sh           |  4 ++--\n t/t6423-merge-rename-directories.sh |  9 +++++++--\n t/t7800-difftool.sh                 |  8 ++++----\n t/t9700/test.pl                     |  9 +++++++--\n 10 files changed, 60 insertions(+), 21 deletions(-)\n\n\nbase-commit: 9a2fb147f2c61d0cab52c883e7e26f5b7948e3ed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2009%2Fdscho%2Fprepare-the-test-suite-for-symlink-support-on-windows-v2\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2009/dscho/prepare-the-test-suite-for-symlink-support-on-windows-v2\nPull-Request: https://github.com/gitgitgadget/git/pull/2009\n\nRange-diff vs v1:\n\n  1:  2d329837e3 =  1:  2d329837e3 t9700: accommodate for Windows paths\n  2:  b97afa9a5c =  2:  b97afa9a5c apply: symbolic links lack a \"trustable executable bit\"\n  3:  96e279f50e =  3:  96e279f50e mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  4:  3be9594e80 !  4:  9639e04ac6 t0001: handle `diff --no-index` gracefully\n     @@ Commit message\n          file mode of 120000). That is totally unexpected by the test case, which\n          as a consequence fails, meaning that it's a bug in the test case itself.\n      \n     +    Co-authored-by: Junio C Hamano <gitster@pobox.com>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## t/t0001-init.sh ##\n     @@ t/t0001-init.sh: test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n       \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n      -\ttest_cmp expected newdir/.git &&\n      +\tcase \"$GIT_TEST_CMP\" in\n     -+\t*--no-index*) ;; # git diff --no-index does not resolve symlinks\n     ++\t# `git diff --no-index` does not resolve symlinks\n     ++\t*--no-index*) cmp expected newdir/.git;;\n      +\t*) test_cmp expected newdir/.git;;\n      +\tesac &&\n       \ttest_cmp expected newdir/here &&\n  5:  c59a5f2478 =  5:  3db0599d91 t0301: another fix for Windows compatibility\n  6:  0866db0a17 !  6:  f2da7d4d50 t0600: fix incomplete prerequisite for a test case\n     @@ Commit message\n          However, the `preferSymlinkRefs` feature is not supported on Windows,\n          therefore this test case needs the `MINGW` prerequisite, too.\n      \n     +    There's a couple more cases where we set this config key:\n     +\n     +      - In a subsequent test in t0600, but there we explicitly set it to\n     +        \"false\". So this would naturally be supported by Windows.\n     +\n     +      - In t7201 we set the value to `yes`, but we never verify that the\n     +        written reference is a symbolic link in the first place. I guess\n     +        that we could rather remove setting the configuration value here, as\n     +        we are about to deprecate support for symrefs via symbolic links in\n     +        the first place. But that's certainly outside of the scope of this\n     +        patch.\n     +\n     +      - In t9903 we do the same, but likewise, we don't check whether the\n     +        written file is a symbolic link.\n     +\n     +    Therefore this seems to be the only instance where the tests actually\n     +    need to be adapted.\n     +\n     +    Helped-by: Patrick Steinhardt <ps@pks.im>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## t/t0600-reffiles-backend.sh ##\n  7:  8a7c68b629 =  7:  ea74e678f9 t1006: accommodate for symlink support in MSYS2\n  8:  930828c693 =  8:  1619ea4a3b t1305: skip symlink tests that do not apply to Windows\n  9:  b622ff822c =  9:  807bb679cd t6423: introduce Windows-specific handling for symlinking to /dev/null\n 10:  f7f1e91cef ! 10:  945306b5d4 t7800: work around the MSYS path conversion on Windows\n     @@ Commit message\n      \n          One instance of this problem can be observed in the 'difftool --dir-diff\n          handles modified symlinks' test case in `t7800-difftool.sh`, which\n     -    assumes that that all absolute paths start with a forward slash. That\n     +    assumes that all absolute paths start with a forward slash. That\n          assumption is incorrect in general, e.g. on Windows, where absolute\n          paths have many shapes and forms, none of which starts with a forward\n          slash.\n\n-- \ngitgitgadget\n"},{"id":"531702","messageId":"b97afa9a5c28aa89fd94f210a0dec5de891eb221.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 02/10] apply: symbolic links lack a \"trustable executable bit\"","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:17Z","receivedAt":"2025-12-05T15:02:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen 0482c32c334b (apply: ignore working tree filemode when\n!core.filemode, 2023-12-26) fixed `git apply` to stop warning about\nexecutable files, it inadvertently changed the code flow also for\nsymbolic links and directories.\n\nLet's narrow the scope of the special `!trust_executable_git` code path\nto apply only to regular files.\n\nThis is needed to let t4115.5(symlink escape when creating new files)\npass on Windows when symbolic link support is enabled in the MSYS2\nruntime.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex a2ceb3fb40..de5750354a 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3779,7 +3779,7 @@ static int check_preimage(struct apply_state *state,\n \t\tif (*ce && !(*ce)->ce_mode)\n \t\t\tBUG(\"ce_mode == 0 for path '%s'\", old_name);\n \n-\t\tif (trust_executable_bit)\n+\t\tif (trust_executable_bit || !S_ISREG(st->st_mode))\n \t\t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n \t\telse if (*ce)\n \t\t\tst_mode = (*ce)->ce_mode;\n-- \ngitgitgadget\n\n"},{"id":"531703","messageId":"2d329837e34a88cfe28be728fe24bb5a2c6a9752.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 01/10] t9700: accommodate for Windows paths","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:16Z","receivedAt":"2025-12-05T15:02:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEver since fe53bbc9beb (Git.pm: Always set Repository to absolute path\nif autodetecting, 2009-05-07), the t9700 test _must_ fail on Windows\nbecause of that age-old Unix paths vs Windows paths problem.\n\nThe underlying root cause is that Git cannot run with a regular Win32\nvariant of Perl, the assumption that every path is a Unix path is just\ntoo strong in Git's Perl code.\n\nAs a consequence, Git for Windows is basically stuck with using the\nMSYS2 variant of Perl which uses a POSIX emulation layer (which is a\nfriendly fork of Cygwin) _and_ a best-effort Unix <-> Windows paths\nconversion whenever crossing the boundary between MSYS2 and regular\nWin32 processes. It is best effort only, though, using heuristics to\nautomagically convert correctly in most cases, but not in all cases.\n\nIn the context of this here patch, this means that asking `git.exe` for\nthe absolute path of the `.git/` directory will return a Win32 path\nbecause `git.exe` is a regular Win32 executable that has no idea about\nUnix-ish paths. But above-mentioned commit introduced a test that wants\nto verify that this path is identical to the one that the Git Perl\nmodule reports (which refuses to use Win32 paths and uses Unix-ish paths\ninstead). Obviously, this must fail because no heuristics can kick in at\nthat layer.\n\nThis test failure has not even been caught when Git introduced Windows\nsupport in its CI definition in 2e90484eb4a (ci: add a Windows job to\nthe Azure Pipelines definition, 2019-01-29), as all tests relying on\nPerl had to be disabled even from the start (because the CI runs would\notherwise have resulted in prohibitively long runtimes, not because\nWindows is super slow per se, but because Git's test suite keeps\ninsisting on using technology that requires a POSIX emulation layer,\nwhich _is_ super slow on Windows).\n\nTo work around this failure, let's use the `cygpath` utility to convert\nthe absolute `gitdir` path into the form that the Perl code expects.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t9700/test.pl | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9700/test.pl b/t/t9700/test.pl\nindex 58a9b328d5..570b0c5680 100755\n--- a/t/t9700/test.pl\n+++ b/t/t9700/test.pl\n@@ -117,7 +117,12 @@ close TEMPFILE;\n unlink $tmpfile;\n \n # paths\n-is($r->repo_path, $abs_repo_dir . \"/.git\", \"repo_path\");\n+my $abs_git_dir = $abs_repo_dir . \"/.git\";\n+if ($^O eq 'msys' or $^O eq 'cygwin') {\n+  $abs_git_dir = `cygpath -am \"$abs_repo_dir/.git\"`;\n+  $abs_git_dir =~ s/\\r?\\n?$//;\n+}\n+is($r->repo_path, $abs_git_dir, \"repo_path\");\n is($r->wc_path, $abs_repo_dir . \"/\", \"wc_path\");\n is($r->wc_subdir, \"\", \"wc_subdir initial\");\n $r->wc_chdir(\"directory1\");\n@@ -127,7 +132,7 @@ is($r->config(\"test.string\"), \"value\", \"config after wc_chdir\");\n # Object generation in sub directory\n chdir(\"directory2\");\n my $r2 = Git->repository();\n-is($r2->repo_path, $abs_repo_dir . \"/.git\", \"repo_path (2)\");\n+is($r2->repo_path, $abs_git_dir, \"repo_path (2)\");\n is($r2->wc_path, $abs_repo_dir . \"/\", \"wc_path (2)\");\n is($r2->wc_subdir, \"directory2/\", \"wc_subdir initial (2)\");\n \n-- \ngitgitgadget\n\n"},{"id":"531706","messageId":"96e279f50ebc26084095e781cf58db233fa05b74.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:18Z","receivedAt":"2025-12-05T15:02:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `_wopen()` function would gladly follow a symbolic link to a\nnon-existent file and create it when given above-mentioned flags.\n\nGit expects the `open()` call to fail, though. So let's add yet another\nwork-around to pretend that Windows behaves like Linux.\n\nThis is required to let t4115.8(--reject removes .rej symlink if it\nexists) pass on Windows when enabling the MSYS2 runtime's symbolic link\nsupport.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.c | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 736a07a028..9fbf12a3d3 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n \twchar_t wfilename[MAX_PATH];\n \topen_fn_t open_fn;\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n \n \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n \n@@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n \telse if (xutftowcs_path(wfilename, filename) < 0)\n \t\treturn -1;\n \n+\t/*\n+\t * When `symlink` exists and is a symbolic link pointing to a\n+\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n+\t * create that file. Not what we want: Linux would say `EEXIST`\n+\t * in that instance, which is therefore what Git expects.\n+\t */\n+\tif (create &&\n+\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n+\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n+\t\terrno = EEXIST;\n+\t\treturn -1;\n+\t}\n+\n \tfd = open_fn(wfilename, oflags, mode);\n \n \t/*\n-- \ngitgitgadget\n\n"},{"id":"531705","messageId":"9639e04ac6208171f6e51077649e82a3be4ac70d.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:19Z","receivedAt":"2025-12-05T15:02:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe test case 're-init to move gitdir symlink' wants to compare the\ncontents of `newdir/.git`, which is a symbolic link pointing to a file.\nHowever, `git diff --no-index`, which is used by `test_cmp` on Windows,\ndoes not resolve symlinks; It shows the symlink _target_ instead (with a\nfile mode of 120000). That is totally unexpected by the test case, which\nas a consequence fails, meaning that it's a bug in the test case itself.\n\nCo-authored-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0001-init.sh | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 618da080dc..e4d32bb4d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n \tgit init --separate-git-dir ../realgitdir\n \t) &&\n \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n-\ttest_cmp expected newdir/.git &&\n+\tcase \"$GIT_TEST_CMP\" in\n+\t# `git diff --no-index` does not resolve symlinks\n+\t*--no-index*) cmp expected newdir/.git;;\n+\t*) test_cmp expected newdir/.git;;\n+\tesac &&\n \ttest_cmp expected newdir/here &&\n \ttest_path_is_dir realgitdir/refs\n '\n-- \ngitgitgadget\n\n"},{"id":"531709","messageId":"3db0599d9151c8c112ee7efe25825fa048769a62.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:20Z","receivedAt":"2025-12-05T15:02:37Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nJust like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\nsuite because that would fail on Windows (because Windows has a much\nmore powerful permission system that cannot be mapped into the simpler\nuser/group/other read/write/execute model).\n\nThere was one forgotten instance of this which was hidden by a `SYMLINK`\nprerequisite. Currently, this prevents this test case from being\nexecuted on Windows, but with the upcoming support for symbolic links,\nit would become a problem.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0301-credential-cache.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\nindex dc30289f75..6f7cfd9e33 100755\n--- a/t/t0301-credential-cache.sh\n+++ b/t/t0301-credential-cache.sh\n@@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n \t\trmdir \\\"\\$HOME/dir/\\\" &&\n \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n \t\" &&\n-\tmkdir -p -m 700 \"$HOME/dir/\" &&\n+\tmkdir -p \"$HOME/dir/\" &&\n+\tchmod 700 \"$HOME/dir/\" &&\n \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n \tcheck approve cache <<-\\EOF &&\n \tprotocol=https\n-- \ngitgitgadget\n\n"},{"id":"531708","messageId":"f2da7d4d503eaf9dabf61a0626be2586f9da835f.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 06/10] t0600: fix incomplete prerequisite for a test case","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:21Z","receivedAt":"2025-12-05T15:02:39Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe 'symref transaction supports symlinks' test case is guarded by the\n`SYMLINK` prerequisite because `core.prefersymlinkrefs = true` requires\nsymbolic links to be supported.\n\nHowever, the `preferSymlinkRefs` feature is not supported on Windows,\ntherefore this test case needs the `MINGW` prerequisite, too.\n\nThere's a couple more cases where we set this config key:\n\n  - In a subsequent test in t0600, but there we explicitly set it to\n    \"false\". So this would naturally be supported by Windows.\n\n  - In t7201 we set the value to `yes`, but we never verify that the\n    written reference is a symbolic link in the first place. I guess\n    that we could rather remove setting the configuration value here, as\n    we are about to deprecate support for symrefs via symbolic links in\n    the first place. But that's certainly outside of the scope of this\n    patch.\n\n  - In t9903 we do the same, but likewise, we don't check whether the\n    written file is a symbolic link.\n\nTherefore this seems to be the only instance where the tests actually\nneed to be adapted.\n\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0600-reffiles-backend.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\nindex b11126ed47..74bfa2e9ba 100755\n--- a/t/t0600-reffiles-backend.sh\n+++ b/t/t0600-reffiles-backend.sh\n@@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '\n \tesac\n '\n \n-test_expect_success SYMLINKS 'symref transaction supports symlinks' '\n+test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '\n \ttest_when_finished \"git symbolic-ref -d TEST_SYMREF_HEAD\" &&\n \tgit update-ref refs/heads/new @ &&\n \ttest_config core.prefersymlinkrefs true &&\n-- \ngitgitgadget\n\n"},{"id":"531710","messageId":"ea74e678f9440a9f42541a8fd207d90b058ce152.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:22Z","receivedAt":"2025-12-05T15:02:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe MSYS2 runtime (which inherits this trait from the Cygwin runtime,\nand which is used by Git for Windows' Bash to emulate POSIX\nfunctionality on Windows, the same Bash that is also used to run Git's\ntest suite on Windows) has a mode where it can create native symbolic\nlinks on Windows.\n\nNaturally, this is a bit of a strange feature, given that Cygwin goes\nout of its way to support Unix-like paths even if no Win32 program\nunderstands those, and the symbolic links have to use Win32 paths\ninstead (which Win32 programs understand very well).\n\nAs a consequence, the symbolic link targets get normalized before the\nlinks are created.\n\nThis results in certain quirks that Git's test suite is ill equipped to\naccommodate (because Git's test suite expects to be able to use\nUnix-like paths even on Windows).\n\nThe test script t1006-cat-file.sh contains two prime examples, two test\ncases that need to skip a couple assertions because they are simply\nwrong in the context of Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1006-cat-file.sh | 24 +++++++++++++++++-------\n 1 file changed, 17 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 1f61b666a7..0eee3bb878 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-\n \techo .. >>expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual &&\n-\techo symlink 3 >expect &&\n-\techo ../ >>expect &&\n+\tif test_have_prereq MINGW,SYMLINKS\n+\tthen\n+\t\ttest_write_lines \"symlink 2\" ..\n+\telse\n+\t\ttest_write_lines \"symlink 3\" ../\n+\tfi >expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n-\techo HEAD: | git cat-file --batch-check >expect &&\n-\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n-\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n+\tif test_have_prereq !MINGW\n+\tthen\n+\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n+\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n+\t\t# different shape than Git expects them.\n+\t\techo HEAD: | git cat-file --batch-check >expect &&\n+\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual\n+\tfi &&\n \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp found actual &&\n \techo symlink 7 >expect &&\n-- \ngitgitgadget\n\n"},{"id":"531707","messageId":"1619ea4a3b0767e6879f41bff6430512b3e8fcbf.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 08/10] t1305: skip symlink tests that do not apply to Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:23Z","receivedAt":"2025-12-05T15:02:42Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn Git for Windows, the gitdir is canonicalized so that even when the\ngitdir is specified via a symbolic link, the `gitdir:` conditional\ninclude will only match the real directory path.\n\nUnfortunately, t1305 codifies a different behavior in two test cases,\nwhich are hereby skipped on Windows.\n\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 8ff2b0c232..6e51f892f3 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '\n \tln -s foo bar &&\n \t(\n \t\tcd bar &&\n@@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '\n \t(\n \t\tcd bar &&\n \t\techo \"[includeIf \\\"gitdir/i:BAR/\\\"]path=bar8\" >>.git/config &&\n-- \ngitgitgadget\n\n"},{"id":"531711","messageId":"807bb679cd8665007d207b8324d1d43e8a5d0fc9.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 09/10] t6423: introduce Windows-specific handling for symlinking to /dev/null","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:24Z","receivedAt":"2025-12-05T15:02:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe device `/dev/null` does not exist on Windows, it's called `NUL`\nthere. Calling `ln -s /dev/null my-symlink` in a symlink-enabled MSYS2\nBash will therefore literally link to a file or directory called `null`\nthat is supposed to be in the current drive's top-level `dev` directory.\nWhich typically does not exist.\n\nThe test, however, really wants the created symbolic link to point to\nthe NUL device. Let's instead use the `mklink` utility on Windows to\nperform that job, and keep using `ln -s /dev/null <target>` on\nnon-Windows platforms.\n\nWhile at it, add the missing `SYMLINKS` prereq because this test _still_\nwould not pass on Windows before support for symbolic links is\nupstreamed from Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6423-merge-rename-directories.sh | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex 533ac85dc8..53535a8ebf 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -5158,13 +5158,18 @@ test_setup_12m () {\n \t\tgit switch B &&\n \t\tgit rm dir/subdir/file &&\n \t\tmkdir dir &&\n-\t\tln -s /dev/null dir/subdir &&\n+\t\tif test_have_prereq MINGW\n+\t\tthen\n+\t\t\tcmd //c 'mklink dir\\subdir NUL'\n+\t\telse\n+\t\t\tln -s /dev/null dir/subdir\n+\t\tfi &&\n \t\tgit add . &&\n \t\tgit commit -m \"B\"\n \t)\n }\n \n-test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\n-- \ngitgitgadget\n\n"},{"id":"531712","messageId":"945306b5d4ed35d317805b35e1c2dd719cc7829f.1764946945.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v2 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-05T15:02:25Z","receivedAt":"2025-12-05T15:02:45Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nGit's test suite's relies on Unix shell scripting, which is\nunderstandable, of course, given Git's firm roots (and indeed, ongoing\nfocus) on Linux.\n\nThis fact, combined with Unix shell scripting's natural\nhabitat -- which is, naturally... *drumroll*... Unix --\noften has unintended side effects, where developers expect the test\nsuite to run in a Unix environment, which is an incorrect assumption.\n\nOne instance of this problem can be observed in the 'difftool --dir-diff\nhandles modified symlinks' test case in `t7800-difftool.sh`, which\nassumes that all absolute paths start with a forward slash. That\nassumption is incorrect in general, e.g. on Windows, where absolute\npaths have many shapes and forms, none of which starts with a forward\nslash.\n\nThe only saving grace is that this test case is currently not run on\nWindows because of the `SYMLINK` prerequisite. However, I am currently\nworking towards upstreaming symbolic link support from Git for Windows\nto upstream Git, which will put a crack into that saving grace.\n\nLet's change that test case so that it does not rely on absolute paths\n(which are passed to the \"external command\" `ls` as parameters and are\ntherefore part of its output, and which the test case wants to filter\nout before verifying that the output is as expected) starting with a\nforward slash. Let's instead rely on the much more reliable fact that\n`ls` will output the path in a line that ends in a colon, and simply\nfilter out those lines by matching said colon instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7800-difftool.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex 9b74db5563..bf0f67378d 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \t\tc\n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \t# The left side contains symlink \"c\" that points to \"b\"\n@@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual\n '\n \n-- \ngitgitgadget\n"},{"id":"531736","messageId":"xmqq8qfg772k.fsf@gitster.g","threadId":"64552","inReplyTo":"8129143e-79fb-cadc-8f88-9c8daa73c317@gmx.de","subject":"Re: [PATCH 05/10] t0301: another fix for Windows compatibility","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-06T01:05:55Z","receivedAt":"2025-12-06T01:05:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> It means that we are punting and are not proactively helping future\n>> developers who may make the same mistake, but we expect it would be\n>> rather rare so I am OK with us making that trade-off.\n>\n> Good, then we're on the same page regarding this approach.\n>\n>> But then can you dial back your condescending tone against those who are\n>> not as familiar as glitches in the Windows port of POSIX shell\n>> environment we use for tests?\n>\n> Please don't read more into my words than merely a large frustration with\n> the state of Git's test suite.\n\nWell, the proposed log message is to help future readers of \"git\nlog\" by explaining the relevant background of what motivated us to\nmake the change.  Knowing that you were frustrated may make them\nsympathize, but it would not help them make robust technical\ndecisions when they need to further change what the patch leaves\nwith us.  At that point, telling them our intentions would help them\navoid breaking us while making the end-result fit better for their\npurpose.  Do we want them to be extra careful not to frustrate you\nspecifically when they make a follow-on work in the same area, or\nsomething?\n"},{"id":"531740","messageId":"xmqqbjkc5p64.fsf@gitster.g","threadId":"64552","inReplyTo":"4cf1c638-3b0b-a36a-ce35-41d55e9fae12@gmx.de","subject":"Re: [PATCH 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-06T02:17:55Z","receivedAt":"2025-12-06T02:17:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> On Sat, 29 Nov 2025, Junio C Hamano wrote:\n>\n>> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n>> writes:\n>> \n>> > From: Johannes Schindelin <johannes.schindelin@gmx.de>\n>> >\n>> > The `_wopen()` function would gladly follow a symbolic link to a\n>> > non-existent file and create it when given above-mentioned flags.\n>> >\n>> > Git expects the `open()` call to fail, though. So let's add yet another\n>> > work-around to pretend that Windows behaves like Linux.\n>> \n>> \"like Linux\" -> \"as POSIX expects\"?\n>> \n>> cf. https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n>\n> You are both correct and incorrect. The behavior I described indeed is not\n> limited to Linux, insofar you are correct. The behavior I wanted to\n> imitate is Linux', though, not POSIX.\n\nWell, I do not think we require our open() to be so Linux specific\nthat other POSIX compliant systems (e.g., BSDs) would fail.\n\nHere, Git expects open() to behave as POSIX specifies, so it is good\nenough to emulate open() to be sufficiently POSIX, not Linux.\nMaking it like Linux is purely _your_ doing.\n\nAnd it would not help future developers who finds this commit by\nreading \"git log\" when they find the code that was changed by this\npatch in \"git blame\" output, and they want to further tweak what is\nleft by this patch to fit their needs better while trying to avoid\nbreaking our intent.  Our intention is never \"open must work like\nLinux, allowing the caller to rely on Linux-specific quirk that\nother POSIX implementations may not have\", but writing the log as if\n\"a work-around to make it work like Linux\" was necessary will\nmislead them.\n\n\n"},{"id":"531892","messageId":"aTfX-gMI1kByV7yA@pks.im","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"Re: [PATCH v2 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-12-09T08:04:10Z","receivedAt":"2025-12-09T08:04:17Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Fri, Dec 05, 2025 at 03:02:15PM +0000, Johannes Schindelin via GitGitGadget wrote:\n> Changes since v1:\n> \n>  * Fixed a grammar issue.\n>  * Using cmp rather than skipping the comparison (thanks Junio).\n>  * Extended a commit message to explain that it covers all the cases where\n>    core.preferSymlinkRefs needs special care.\n\nThanks, the range-diff looks good to me!\n\nPatrick\n"},{"id":"531922","messageId":"xmqq7buvjo3r.fsf@gitster.g","threadId":"64552","inReplyTo":"aTfX-gMI1kByV7yA@pks.im","subject":"Re: [PATCH v2 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-09T22:18:32Z","receivedAt":"2025-12-09T22:18:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Fri, Dec 05, 2025 at 03:02:15PM +0000, Johannes Schindelin via GitGitGadget wrote:\n>> Changes since v1:\n>> \n>>  * Fixed a grammar issue.\n>>  * Using cmp rather than skipping the comparison (thanks Junio).\n>>  * Extended a commit message to explain that it covers all the cases where\n>>    core.preferSymlinkRefs needs special care.\n>\n> Thanks, the range-diff looks good to me!\n>\n> Patrick\n\nThanks, both.  Queued.\n"},{"id":"532260","messageId":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v2.git.1764946945.gitgitgadget@gmail.com","subject":"[PATCH v3 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:07Z","receivedAt":"2025-12-16T11:46:20Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git for Windows has supported symbolic links for quite some time: In\nhttps://github.com/git-for-windows/git/pull/156, this support was introduced\nalready into Git for Windows v2.4.2.windows.1 in May 2015.\n\nHowever, the Git for Windows CI never ran the test suite with symbolic link\nsupport because the MSYS2 runtime (i.e. the POSIX emulation layer required\nto run Git's test suite because the latter is written in Unix shell script)\ndoes not support symbolic links right out of the box. This is for historical\nreasons: Symbolic link support was introduced in Windows 7, where these\nlinks could only be created by administrators by default, and it took until\nWindows 10 Build 14972 that at least in Developer Mode, non-administrators\nwould be permitted to create them.\n\nThe MSYS2 runtime does have some sort of support for symbolic links,\nalthough with caveats: seeing as it expects the inputs as Unix-like paths,\nbut the outputs need to be Win32 symbolic links pointing to Win32 paths,\nsome normalization has to be performed in the process. This leads to\nsometimes surprising behavior e.g. when a link target like a/b/.. is\nnormalized to a.\n\nIt has been a minute or three since the time when Windows versions without\nsymbolic link support were common, therefore there are plans to turn on that\nsupport in the MSYS2 runtime on these Windows versions by default, see\nhttps://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n\nTo prepare for this, I am working toward upstreaming Git for Windows' own\nsupport for symbolic links. And to prepare for that, in turn, I am hereby\ncontributing preemptively the fixes required to eventually let Git's test\nsuite pass when both MSYS2 runtime and Git support symbolic links.\n\nAs a bonus, this patch series also contains fixes for the Perl tests (which\nwere broken for a few years, unnoticed because the CI runs need to save on\nruntime and therefore skip the Perl tests because the consume a lot of\ntime).\n\nChanges since v2:\n\n * Polished commit messages.\n * \n\nChanges since v1:\n\n * Fixed a grammar issue.\n * Using cmp rather than skipping the comparison (thanks Junio).\n * Extended a commit message to explain that it covers all the cases where\n   core.preferSymlinkRefs needs special care.\n\nJohannes Schindelin (10):\n  t9700: accommodate for Windows paths\n  apply: symbolic links lack a \"trustable executable bit\"\n  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  t0001: handle `diff --no-index` gracefully\n  t0301: another fix for Windows compatibility\n  t0600: fix incomplete prerequisite for a test case\n  t1006: accommodate for symlink support in MSYS2\n  t1305: skip symlink tests that do not apply to Windows\n  t6423: introduce Windows-specific handling for symlinking to /dev/null\n  t7800: work around the MSYS path conversion on Windows\n\n apply.c                             |  2 +-\n compat/mingw.c                      | 14 ++++++++++++++\n t/t0001-init.sh                     |  6 +++++-\n t/t0301-credential-cache.sh         |  3 ++-\n t/t0600-reffiles-backend.sh         |  2 +-\n t/t1006-cat-file.sh                 | 24 +++++++++++++++++-------\n t/t1305-config-include.sh           |  4 ++--\n t/t6423-merge-rename-directories.sh |  9 +++++++--\n t/t7800-difftool.sh                 |  8 ++++----\n t/t9700/test.pl                     |  9 +++++++--\n 10 files changed, 60 insertions(+), 21 deletions(-)\n\n\nbase-commit: 9a2fb147f2c61d0cab52c883e7e26f5b7948e3ed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2009%2Fdscho%2Fprepare-the-test-suite-for-symlink-support-on-windows-v3\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2009/dscho/prepare-the-test-suite-for-symlink-support-on-windows-v3\nPull-Request: https://github.com/gitgitgadget/git/pull/2009\n\nRange-diff vs v2:\n\n  1:  2d329837e3 =  1:  2d329837e3 t9700: accommodate for Windows paths\n  2:  b97afa9a5c =  2:  b97afa9a5c apply: symbolic links lack a \"trustable executable bit\"\n  3:  96e279f50e !  3:  f42a2f14bc mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n     @@ Commit message\n          non-existent file and create it when given above-mentioned flags.\n      \n          Git expects the `open()` call to fail, though. So let's add yet another\n     -    work-around to pretend that Windows behaves like Linux.\n     +    work-around to pretend that Windows behaves according to POSIX, see:\n     +    https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n      \n          This is required to let t4115.8(--reject removes .rej symlink if it\n          exists) pass on Windows when enabling the MSYS2 runtime's symbolic link\n  4:  9639e04ac6 =  4:  70237394c6 t0001: handle `diff --no-index` gracefully\n  5:  3db0599d91 !  5:  0d371ee552 t0301: another fix for Windows compatibility\n     @@ Commit message\n      \n          Just like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n          2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\n     -    suite because that would fail on Windows (because Windows has a much\n     -    more powerful permission system that cannot be mapped into the simpler\n     -    user/group/other read/write/execute model).\n     +    suite because that would fail on Windows.\n      \n          There was one forgotten instance of this which was hidden by a `SYMLINK`\n          prerequisite. Currently, this prevents this test case from being\n  6:  f2da7d4d50 !  6:  91bd72062c t0600: fix incomplete prerequisite for a test case\n     @@ Commit message\n          However, the `preferSymlinkRefs` feature is not supported on Windows,\n          therefore this test case needs the `MINGW` prerequisite, too.\n      \n     -    There's a couple more cases where we set this config key:\n     -\n     -      - In a subsequent test in t0600, but there we explicitly set it to\n     -        \"false\". So this would naturally be supported by Windows.\n     -\n     -      - In t7201 we set the value to `yes`, but we never verify that the\n     -        written reference is a symbolic link in the first place. I guess\n     -        that we could rather remove setting the configuration value here, as\n     -        we are about to deprecate support for symrefs via symbolic links in\n     -        the first place. But that's certainly outside of the scope of this\n     -        patch.\n     -\n     -      - In t9903 we do the same, but likewise, we don't check whether the\n     -        written file is a symbolic link.\n     -\n     -    Therefore this seems to be the only instance where the tests actually\n     -    need to be adapted.\n     -\n     -    Helped-by: Patrick Steinhardt <ps@pks.im>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## t/t0600-reffiles-backend.sh ##\n  7:  ea74e678f9 =  7:  c2d3212f11 t1006: accommodate for symlink support in MSYS2\n  8:  1619ea4a3b =  8:  03ff6d756d t1305: skip symlink tests that do not apply to Windows\n  9:  807bb679cd =  9:  4ab6aaf2cf t6423: introduce Windows-specific handling for symlinking to /dev/null\n 10:  945306b5d4 = 10:  5f056902df t7800: work around the MSYS path conversion on Windows\n\n-- \ngitgitgadget\n"},{"id":"532261","messageId":"2d329837e34a88cfe28be728fe24bb5a2c6a9752.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 01/10] t9700: accommodate for Windows paths","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:08Z","receivedAt":"2025-12-16T11:46:21Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEver since fe53bbc9beb (Git.pm: Always set Repository to absolute path\nif autodetecting, 2009-05-07), the t9700 test _must_ fail on Windows\nbecause of that age-old Unix paths vs Windows paths problem.\n\nThe underlying root cause is that Git cannot run with a regular Win32\nvariant of Perl, the assumption that every path is a Unix path is just\ntoo strong in Git's Perl code.\n\nAs a consequence, Git for Windows is basically stuck with using the\nMSYS2 variant of Perl which uses a POSIX emulation layer (which is a\nfriendly fork of Cygwin) _and_ a best-effort Unix <-> Windows paths\nconversion whenever crossing the boundary between MSYS2 and regular\nWin32 processes. It is best effort only, though, using heuristics to\nautomagically convert correctly in most cases, but not in all cases.\n\nIn the context of this here patch, this means that asking `git.exe` for\nthe absolute path of the `.git/` directory will return a Win32 path\nbecause `git.exe` is a regular Win32 executable that has no idea about\nUnix-ish paths. But above-mentioned commit introduced a test that wants\nto verify that this path is identical to the one that the Git Perl\nmodule reports (which refuses to use Win32 paths and uses Unix-ish paths\ninstead). Obviously, this must fail because no heuristics can kick in at\nthat layer.\n\nThis test failure has not even been caught when Git introduced Windows\nsupport in its CI definition in 2e90484eb4a (ci: add a Windows job to\nthe Azure Pipelines definition, 2019-01-29), as all tests relying on\nPerl had to be disabled even from the start (because the CI runs would\notherwise have resulted in prohibitively long runtimes, not because\nWindows is super slow per se, but because Git's test suite keeps\ninsisting on using technology that requires a POSIX emulation layer,\nwhich _is_ super slow on Windows).\n\nTo work around this failure, let's use the `cygpath` utility to convert\nthe absolute `gitdir` path into the form that the Perl code expects.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t9700/test.pl | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9700/test.pl b/t/t9700/test.pl\nindex 58a9b328d5..570b0c5680 100755\n--- a/t/t9700/test.pl\n+++ b/t/t9700/test.pl\n@@ -117,7 +117,12 @@ close TEMPFILE;\n unlink $tmpfile;\n \n # paths\n-is($r->repo_path, $abs_repo_dir . \"/.git\", \"repo_path\");\n+my $abs_git_dir = $abs_repo_dir . \"/.git\";\n+if ($^O eq 'msys' or $^O eq 'cygwin') {\n+  $abs_git_dir = `cygpath -am \"$abs_repo_dir/.git\"`;\n+  $abs_git_dir =~ s/\\r?\\n?$//;\n+}\n+is($r->repo_path, $abs_git_dir, \"repo_path\");\n is($r->wc_path, $abs_repo_dir . \"/\", \"wc_path\");\n is($r->wc_subdir, \"\", \"wc_subdir initial\");\n $r->wc_chdir(\"directory1\");\n@@ -127,7 +132,7 @@ is($r->config(\"test.string\"), \"value\", \"config after wc_chdir\");\n # Object generation in sub directory\n chdir(\"directory2\");\n my $r2 = Git->repository();\n-is($r2->repo_path, $abs_repo_dir . \"/.git\", \"repo_path (2)\");\n+is($r2->repo_path, $abs_git_dir, \"repo_path (2)\");\n is($r2->wc_path, $abs_repo_dir . \"/\", \"wc_path (2)\");\n is($r2->wc_subdir, \"directory2/\", \"wc_subdir initial (2)\");\n \n-- \ngitgitgadget\n\n"},{"id":"532262","messageId":"b97afa9a5c28aa89fd94f210a0dec5de891eb221.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 02/10] apply: symbolic links lack a \"trustable executable bit\"","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:09Z","receivedAt":"2025-12-16T11:46:22Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen 0482c32c334b (apply: ignore working tree filemode when\n!core.filemode, 2023-12-26) fixed `git apply` to stop warning about\nexecutable files, it inadvertently changed the code flow also for\nsymbolic links and directories.\n\nLet's narrow the scope of the special `!trust_executable_git` code path\nto apply only to regular files.\n\nThis is needed to let t4115.5(symlink escape when creating new files)\npass on Windows when symbolic link support is enabled in the MSYS2\nruntime.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex a2ceb3fb40..de5750354a 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3779,7 +3779,7 @@ static int check_preimage(struct apply_state *state,\n \t\tif (*ce && !(*ce)->ce_mode)\n \t\t\tBUG(\"ce_mode == 0 for path '%s'\", old_name);\n \n-\t\tif (trust_executable_bit)\n+\t\tif (trust_executable_bit || !S_ISREG(st->st_mode))\n \t\t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n \t\telse if (*ce)\n \t\t\tst_mode = (*ce)->ce_mode;\n-- \ngitgitgadget\n\n"},{"id":"532263","messageId":"f42a2f14bce6920200e4ee993b76b37d4a762441.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:10Z","receivedAt":"2025-12-16T11:46:24Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `_wopen()` function would gladly follow a symbolic link to a\nnon-existent file and create it when given above-mentioned flags.\n\nGit expects the `open()` call to fail, though. So let's add yet another\nwork-around to pretend that Windows behaves according to POSIX, see:\nhttps://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n\nThis is required to let t4115.8(--reject removes .rej symlink if it\nexists) pass on Windows when enabling the MSYS2 runtime's symbolic link\nsupport.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.c | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 736a07a028..9fbf12a3d3 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n \twchar_t wfilename[MAX_PATH];\n \topen_fn_t open_fn;\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n \n \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n \n@@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n \telse if (xutftowcs_path(wfilename, filename) < 0)\n \t\treturn -1;\n \n+\t/*\n+\t * When `symlink` exists and is a symbolic link pointing to a\n+\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n+\t * create that file. Not what we want: Linux would say `EEXIST`\n+\t * in that instance, which is therefore what Git expects.\n+\t */\n+\tif (create &&\n+\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n+\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n+\t\terrno = EEXIST;\n+\t\treturn -1;\n+\t}\n+\n \tfd = open_fn(wfilename, oflags, mode);\n \n \t/*\n-- \ngitgitgadget\n\n"},{"id":"532264","messageId":"70237394c64101b3d70a1d31bd4a763997474cb1.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:11Z","receivedAt":"2025-12-16T11:46:25Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe test case 're-init to move gitdir symlink' wants to compare the\ncontents of `newdir/.git`, which is a symbolic link pointing to a file.\nHowever, `git diff --no-index`, which is used by `test_cmp` on Windows,\ndoes not resolve symlinks; It shows the symlink _target_ instead (with a\nfile mode of 120000). That is totally unexpected by the test case, which\nas a consequence fails, meaning that it's a bug in the test case itself.\n\nCo-authored-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0001-init.sh | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 618da080dc..e4d32bb4d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n \tgit init --separate-git-dir ../realgitdir\n \t) &&\n \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n-\ttest_cmp expected newdir/.git &&\n+\tcase \"$GIT_TEST_CMP\" in\n+\t# `git diff --no-index` does not resolve symlinks\n+\t*--no-index*) cmp expected newdir/.git;;\n+\t*) test_cmp expected newdir/.git;;\n+\tesac &&\n \ttest_cmp expected newdir/here &&\n \ttest_path_is_dir realgitdir/refs\n '\n-- \ngitgitgadget\n\n"},{"id":"532265","messageId":"0d371ee552a0fd8aaad9e94c3a7477823852d25e.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:12Z","receivedAt":"2025-12-16T11:46:27Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nJust like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\nsuite because that would fail on Windows.\n\nThere was one forgotten instance of this which was hidden by a `SYMLINK`\nprerequisite. Currently, this prevents this test case from being\nexecuted on Windows, but with the upcoming support for symbolic links,\nit would become a problem.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0301-credential-cache.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\nindex dc30289f75..6f7cfd9e33 100755\n--- a/t/t0301-credential-cache.sh\n+++ b/t/t0301-credential-cache.sh\n@@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n \t\trmdir \\\"\\$HOME/dir/\\\" &&\n \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n \t\" &&\n-\tmkdir -p -m 700 \"$HOME/dir/\" &&\n+\tmkdir -p \"$HOME/dir/\" &&\n+\tchmod 700 \"$HOME/dir/\" &&\n \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n \tcheck approve cache <<-\\EOF &&\n \tprotocol=https\n-- \ngitgitgadget\n\n"},{"id":"532266","messageId":"c2d3212f11ada7a0cae66812938b3d88a186a4ed.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:14Z","receivedAt":"2025-12-16T11:46:29Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe MSYS2 runtime (which inherits this trait from the Cygwin runtime,\nand which is used by Git for Windows' Bash to emulate POSIX\nfunctionality on Windows, the same Bash that is also used to run Git's\ntest suite on Windows) has a mode where it can create native symbolic\nlinks on Windows.\n\nNaturally, this is a bit of a strange feature, given that Cygwin goes\nout of its way to support Unix-like paths even if no Win32 program\nunderstands those, and the symbolic links have to use Win32 paths\ninstead (which Win32 programs understand very well).\n\nAs a consequence, the symbolic link targets get normalized before the\nlinks are created.\n\nThis results in certain quirks that Git's test suite is ill equipped to\naccommodate (because Git's test suite expects to be able to use\nUnix-like paths even on Windows).\n\nThe test script t1006-cat-file.sh contains two prime examples, two test\ncases that need to skip a couple assertions because they are simply\nwrong in the context of Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1006-cat-file.sh | 24 +++++++++++++++++-------\n 1 file changed, 17 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 1f61b666a7..0eee3bb878 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-\n \techo .. >>expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual &&\n-\techo symlink 3 >expect &&\n-\techo ../ >>expect &&\n+\tif test_have_prereq MINGW,SYMLINKS\n+\tthen\n+\t\ttest_write_lines \"symlink 2\" ..\n+\telse\n+\t\ttest_write_lines \"symlink 3\" ../\n+\tfi >expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n-\techo HEAD: | git cat-file --batch-check >expect &&\n-\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n-\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n+\tif test_have_prereq !MINGW\n+\tthen\n+\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n+\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n+\t\t# different shape than Git expects them.\n+\t\techo HEAD: | git cat-file --batch-check >expect &&\n+\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual\n+\tfi &&\n \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp found actual &&\n \techo symlink 7 >expect &&\n-- \ngitgitgadget\n\n"},{"id":"532267","messageId":"03ff6d756d323616b16089b92afeb9a2617518f5.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 08/10] t1305: skip symlink tests that do not apply to Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:15Z","receivedAt":"2025-12-16T11:46:30Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn Git for Windows, the gitdir is canonicalized so that even when the\ngitdir is specified via a symbolic link, the `gitdir:` conditional\ninclude will only match the real directory path.\n\nUnfortunately, t1305 codifies a different behavior in two test cases,\nwhich are hereby skipped on Windows.\n\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 8ff2b0c232..6e51f892f3 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '\n \tln -s foo bar &&\n \t(\n \t\tcd bar &&\n@@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '\n \t(\n \t\tcd bar &&\n \t\techo \"[includeIf \\\"gitdir/i:BAR/\\\"]path=bar8\" >>.git/config &&\n-- \ngitgitgadget\n\n"},{"id":"532268","messageId":"4ab6aaf2cf20d2508ae5a816ec7932c8e9c4e639.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 09/10] t6423: introduce Windows-specific handling for symlinking to /dev/null","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:16Z","receivedAt":"2025-12-16T11:46:32Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe device `/dev/null` does not exist on Windows, it's called `NUL`\nthere. Calling `ln -s /dev/null my-symlink` in a symlink-enabled MSYS2\nBash will therefore literally link to a file or directory called `null`\nthat is supposed to be in the current drive's top-level `dev` directory.\nWhich typically does not exist.\n\nThe test, however, really wants the created symbolic link to point to\nthe NUL device. Let's instead use the `mklink` utility on Windows to\nperform that job, and keep using `ln -s /dev/null <target>` on\nnon-Windows platforms.\n\nWhile at it, add the missing `SYMLINKS` prereq because this test _still_\nwould not pass on Windows before support for symbolic links is\nupstreamed from Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6423-merge-rename-directories.sh | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex 533ac85dc8..53535a8ebf 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -5158,13 +5158,18 @@ test_setup_12m () {\n \t\tgit switch B &&\n \t\tgit rm dir/subdir/file &&\n \t\tmkdir dir &&\n-\t\tln -s /dev/null dir/subdir &&\n+\t\tif test_have_prereq MINGW\n+\t\tthen\n+\t\t\tcmd //c 'mklink dir\\subdir NUL'\n+\t\telse\n+\t\t\tln -s /dev/null dir/subdir\n+\t\tfi &&\n \t\tgit add . &&\n \t\tgit commit -m \"B\"\n \t)\n }\n \n-test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\n-- \ngitgitgadget\n\n"},{"id":"532269","messageId":"5f056902df52aa64ae92c37ff4ac161701b4bd71.1765885577.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v3 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-16T11:46:17Z","receivedAt":"2025-12-16T11:46:33Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nGit's test suite's relies on Unix shell scripting, which is\nunderstandable, of course, given Git's firm roots (and indeed, ongoing\nfocus) on Linux.\n\nThis fact, combined with Unix shell scripting's natural\nhabitat -- which is, naturally... *drumroll*... Unix --\noften has unintended side effects, where developers expect the test\nsuite to run in a Unix environment, which is an incorrect assumption.\n\nOne instance of this problem can be observed in the 'difftool --dir-diff\nhandles modified symlinks' test case in `t7800-difftool.sh`, which\nassumes that all absolute paths start with a forward slash. That\nassumption is incorrect in general, e.g. on Windows, where absolute\npaths have many shapes and forms, none of which starts with a forward\nslash.\n\nThe only saving grace is that this test case is currently not run on\nWindows because of the `SYMLINK` prerequisite. However, I am currently\nworking towards upstreaming symbolic link support from Git for Windows\nto upstream Git, which will put a crack into that saving grace.\n\nLet's change that test case so that it does not rely on absolute paths\n(which are passed to the \"external command\" `ls` as parameters and are\ntherefore part of its output, and which the test case wants to filter\nout before verifying that the output is as expected) starting with a\nforward slash. Let's instead rely on the much more reliable fact that\n`ls` will output the path in a line that ends in a colon, and simply\nfilter out those lines by matching said colon instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7800-difftool.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex 9b74db5563..bf0f67378d 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \t\tc\n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \t# The left side contains symlink \"c\" that points to \"b\"\n@@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual\n '\n \n-- \ngitgitgadget\n"},{"id":"532297","messageId":"xmqq345a46b1.fsf@gitster.g","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"Re: [PATCH v3 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-16T18:42:26Z","receivedAt":"2025-12-16T18:42:29Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> It has been a minute or three since the time when Windows versions without\n> symbolic link support were common, therefore there are plans to turn on that\n> support in the MSYS2 runtime on these Windows versions by default, see\n> https://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n>\n> To prepare for this, I am working toward upstreaming Git for Windows' own\n> support for symbolic links. And to prepare for that, in turn, I am hereby\n> contributing preemptively the fixes required to eventually let Git's test\n> suite pass when both MSYS2 runtime and Git support symbolic links.\n>\n> As a bonus, this patch series also contains fixes for the Perl tests (which\n> were broken for a few years, unnoticed because the CI runs need to save on\n> runtime and therefore skip the Perl tests because the consume a lot of\n> time).\n\nGreat to hear a good news.\n\n> Changes since v2:\n>\n>  * Polished commit messages.\n>  * \n>\n> Changes since v1:\n> ...\n\nCurious what the second bullet point was ;-)\n\nThe step [6/10] somehow did not make the list.  I can reconstruct it\nby looking at the range-diff below (i.e., no content changes, just\nremoval of bunch of lines from the proposed log message and credit\nfor Patrick), but it briefly made me wonder if steps 6-10 from\nposted version left your repository a bit prematurely and they\nwanted to have a bit more work on them, to be described on the empty\nbullet point (*) line above.\n\nIn any case, thanks for updates.  I didn't see anything wrong in\nwhat was shown in the range diff for [01-05/10].  Will replace what\nhas been queued.\n\n> Range-diff vs v2:\n>\n>   1:  2d329837e3 =  1:  2d329837e3 t9700: accommodate for Windows paths\n>   2:  b97afa9a5c =  2:  b97afa9a5c apply: symbolic links lack a \"trustable executable bit\"\n>   3:  96e279f50e !  3:  f42a2f14bc mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n>      @@ Commit message\n>           non-existent file and create it when given above-mentioned flags.\n>       \n>           Git expects the `open()` call to fail, though. So let's add yet another\n>      -    work-around to pretend that Windows behaves like Linux.\n>      +    work-around to pretend that Windows behaves according to POSIX, see:\n>      +    https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n>       \n>           This is required to let t4115.8(--reject removes .rej symlink if it\n>           exists) pass on Windows when enabling the MSYS2 runtime's symbolic link\n>   4:  9639e04ac6 =  4:  70237394c6 t0001: handle `diff --no-index` gracefully\n>   5:  3db0599d91 !  5:  0d371ee552 t0301: another fix for Windows compatibility\n>      @@ Commit message\n>       \n>           Just like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n>           2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\n>      -    suite because that would fail on Windows (because Windows has a much\n>      -    more powerful permission system that cannot be mapped into the simpler\n>      -    user/group/other read/write/execute model).\n>      +    suite because that would fail on Windows.\n>       \n>           There was one forgotten instance of this which was hidden by a `SYMLINK`\n>           prerequisite. Currently, this prevents this test case from being\n>   6:  f2da7d4d50 !  6:  91bd72062c t0600: fix incomplete prerequisite for a test case\n>      @@ Commit message\n>           However, the `preferSymlinkRefs` feature is not supported on Windows,\n>           therefore this test case needs the `MINGW` prerequisite, too.\n>       \n>      -    There's a couple more cases where we set this config key:\n>      -\n>      -      - In a subsequent test in t0600, but there we explicitly set it to\n>      -        \"false\". So this would naturally be supported by Windows.\n>      -\n>      -      - In t7201 we set the value to `yes`, but we never verify that the\n>      -        written reference is a symbolic link in the first place. I guess\n>      -        that we could rather remove setting the configuration value here, as\n>      -        we are about to deprecate support for symrefs via symbolic links in\n>      -        the first place. But that's certainly outside of the scope of this\n>      -        patch.\n>      -\n>      -      - In t9903 we do the same, but likewise, we don't check whether the\n>      -        written file is a symbolic link.\n>      -\n>      -    Therefore this seems to be the only instance where the tests actually\n>      -    need to be adapted.\n>      -\n>      -    Helped-by: Patrick Steinhardt <ps@pks.im>\n>           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n>       \n>        ## t/t0600-reffiles-backend.sh ##\n>   7:  ea74e678f9 =  7:  c2d3212f11 t1006: accommodate for symlink support in MSYS2\n>   8:  1619ea4a3b =  8:  03ff6d756d t1305: skip symlink tests that do not apply to Windows\n>   9:  807bb679cd =  9:  4ab6aaf2cf t6423: introduce Windows-specific handling for symlinking to /dev/null\n>  10:  945306b5d4 = 10:  5f056902df t7800: work around the MSYS path conversion on Windows\n"},{"id":"532305","messageId":"af386607-127c-9acd-6d08-89380c1df570@gmx.de","threadId":"64552","inReplyTo":"xmqq345a46b1.fsf@gitster.g","subject":"Re: [PATCH v3 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2025-12-16T19:35:05Z","receivedAt":"2025-12-16T19:35:12Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Junio,\n\nOn Tue, 16 Dec 2025, Junio C Hamano wrote:\n\n> \"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\n> writes:\n> \n> > It has been a minute or three since the time when Windows versions without\n> > symbolic link support were common, therefore there are plans to turn on that\n> > support in the MSYS2 runtime on these Windows versions by default, see\n> > https://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n> >\n> > To prepare for this, I am working toward upstreaming Git for Windows' own\n> > support for symbolic links. And to prepare for that, in turn, I am hereby\n> > contributing preemptively the fixes required to eventually let Git's test\n> > suite pass when both MSYS2 runtime and Git support symbolic links.\n> >\n> > As a bonus, this patch series also contains fixes for the Perl tests (which\n> > were broken for a few years, unnoticed because the CI runs need to save on\n> > runtime and therefore skip the Perl tests because the consume a lot of\n> > time).\n> \n> Great to hear a good news.\n\nFWIW this was part of v1 already:\nhttps://lore.kernel.org/git/2d329837e34a88cfe28be728fe24bb5a2c6a9752.1764440906.git.gitgitgadget@gmail.com/\n\n> \n> > Changes since v2:\n> >\n> >  * Polished commit messages.\n> >  * \n\nThat was just an oversight: GitHub continues enumerations on the next\nline.\n\n> > Changes since v1:\n> > ...\n> \n> Curious what the second bullet point was ;-)\n> \n> The step [6/10] somehow did not make the list.\n\nStrange. I found a bounce, with this incredibly illuminating message:\n\n\tMessage rejected. For more information, go to https://support.google.com/mail/answer/69585\n\nThat's it. That's the entire message. If you can make any sense of this,\nI'd be quite interested to learn something new.\n\n> I can reconstruct it\n\n... by fetching from the tag that is mentioned in the cover letter. That's\nwhat Git is really good at, after all, fetching code changes.\n\n> by looking at the range-diff below (i.e., no content changes, just\n> removal of bunch of lines from the proposed log message and credit\n> for Patrick),\n\n... which suggests that I simply made a rebasing mistake and accidentally\ndropped the credit, and did not notice it in the range-diff because I had\nbeen staring at the diffs for too long. That's exactly what happened,\nplease reuse the version from v2.\n\nCiao,\nJohannes\n\n> but it briefly made me wonder if steps 6-10 from posted version left\n> your repository a bit prematurely and they wanted to have a bit more\n> work on them, to be described on the empty bullet point (*) line above.\n> \n> In any case, thanks for updates.  I didn't see anything wrong in\n> what was shown in the range diff for [01-05/10].  Will replace what\n> has been queued.\n> \n> > Range-diff vs v2:\n> >\n> >   1:  2d329837e3 =  1:  2d329837e3 t9700: accommodate for Windows paths\n> >   2:  b97afa9a5c =  2:  b97afa9a5c apply: symbolic links lack a \"trustable executable bit\"\n> >   3:  96e279f50e !  3:  f42a2f14bc mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n> >      @@ Commit message\n> >           non-existent file and create it when given above-mentioned flags.\n> >       \n> >           Git expects the `open()` call to fail, though. So let's add yet another\n> >      -    work-around to pretend that Windows behaves like Linux.\n> >      +    work-around to pretend that Windows behaves according to POSIX, see:\n> >      +    https://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n> >       \n> >           This is required to let t4115.8(--reject removes .rej symlink if it\n> >           exists) pass on Windows when enabling the MSYS2 runtime's symbolic link\n> >   4:  9639e04ac6 =  4:  70237394c6 t0001: handle `diff --no-index` gracefully\n> >   5:  3db0599d91 !  5:  0d371ee552 t0301: another fix for Windows compatibility\n> >      @@ Commit message\n> >       \n> >           Just like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n> >           2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\n> >      -    suite because that would fail on Windows (because Windows has a much\n> >      -    more powerful permission system that cannot be mapped into the simpler\n> >      -    user/group/other read/write/execute model).\n> >      +    suite because that would fail on Windows.\n> >       \n> >           There was one forgotten instance of this which was hidden by a `SYMLINK`\n> >           prerequisite. Currently, this prevents this test case from being\n> >   6:  f2da7d4d50 !  6:  91bd72062c t0600: fix incomplete prerequisite for a test case\n> >      @@ Commit message\n> >           However, the `preferSymlinkRefs` feature is not supported on Windows,\n> >           therefore this test case needs the `MINGW` prerequisite, too.\n> >       \n> >      -    There's a couple more cases where we set this config key:\n> >      -\n> >      -      - In a subsequent test in t0600, but there we explicitly set it to\n> >      -        \"false\". So this would naturally be supported by Windows.\n> >      -\n> >      -      - In t7201 we set the value to `yes`, but we never verify that the\n> >      -        written reference is a symbolic link in the first place. I guess\n> >      -        that we could rather remove setting the configuration value here, as\n> >      -        we are about to deprecate support for symrefs via symbolic links in\n> >      -        the first place. But that's certainly outside of the scope of this\n> >      -        patch.\n> >      -\n> >      -      - In t9903 we do the same, but likewise, we don't check whether the\n> >      -        written file is a symbolic link.\n> >      -\n> >      -    Therefore this seems to be the only instance where the tests actually\n> >      -    need to be adapted.\n> >      -\n> >      -    Helped-by: Patrick Steinhardt <ps@pks.im>\n> >           Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n> >       \n> >        ## t/t0600-reffiles-backend.sh ##\n> >   7:  ea74e678f9 =  7:  c2d3212f11 t1006: accommodate for symlink support in MSYS2\n> >   8:  1619ea4a3b =  8:  03ff6d756d t1305: skip symlink tests that do not apply to Windows\n> >   9:  807bb679cd =  9:  4ab6aaf2cf t6423: introduce Windows-specific handling for symlinking to /dev/null\n> >  10:  945306b5d4 = 10:  5f056902df t7800: work around the MSYS path conversion on Windows\n> \n> \n"},{"id":"532315","messageId":"xmqqms3h3f17.fsf@gitster.g","threadId":"64552","inReplyTo":"af386607-127c-9acd-6d08-89380c1df570@gmx.de","subject":"Re: [PATCH v3 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-17T04:31:32Z","receivedAt":"2025-12-17T04:31:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n>> by looking at the range-diff below (i.e., no content changes, just\n>> removal of bunch of lines from the proposed log message and credit\n>> for Patrick),\n>\n> ... which suggests that I simply made a rebasing mistake and accidentally\n> dropped the credit, and did not notice it in the range-diff because I had\n> been staring at the diffs for too long. That's exactly what happened,\n> please reuse the version from v2.\n\nOK.  If I am reading you correctly, fetching from the v3 pull\nrequest tag would not solve the breakage in [06/10], right?\n\nre there similar \"oops, I meant to change this and that but the\nresulting tree did not get any of them\" for steps [07-10/10], which\ndid not see any changes in the messages on the list?  Presumably, it\nwould not help these steps if I fetching from the v3 pull request\ntag, either, right?\n\nThanks.\n"},{"id":"532351","messageId":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v3.git.1765885577.gitgitgadget@gmail.com","subject":"[PATCH v4 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:36Z","receivedAt":"2025-12-17T14:18:49Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Git for Windows has supported symbolic links for quite some time: In\nhttps://github.com/git-for-windows/git/pull/156, this support was introduced\nalready into Git for Windows v2.4.2.windows.1 in May 2015.\n\nHowever, the Git for Windows CI never ran the test suite with symbolic link\nsupport because the MSYS2 runtime (i.e. the POSIX emulation layer required\nto run Git's test suite because the latter is written in Unix shell script)\ndoes not support symbolic links right out of the box. This is for historical\nreasons: Symbolic link support was introduced in Windows 7, where these\nlinks could only be created by administrators by default, and it took until\nWindows 10 Build 14972 that at least in Developer Mode, non-administrators\nwould be permitted to create them.\n\nThe MSYS2 runtime does have some sort of support for symbolic links,\nalthough with caveats: seeing as it expects the inputs as Unix-like paths,\nbut the outputs need to be Win32 symbolic links pointing to Win32 paths,\nsome normalization has to be performed in the process. This leads to\nsometimes surprising behavior e.g. when a link target like a/b/.. is\nnormalized to a.\n\nIt has been a minute or three since the time when Windows versions without\nsymbolic link support were common, therefore there are plans to turn on that\nsupport in the MSYS2 runtime on these Windows versions by default, see\nhttps://github.com/msys2/msys2-runtime/pull/114 for more details about this.\n\nTo prepare for this, I am working toward upstreaming Git for Windows' own\nsupport for symbolic links. And to prepare for that, in turn, I am hereby\ncontributing preemptively the fixes required to eventually let Git's test\nsuite pass when both MSYS2 runtime and Git support symbolic links.\n\nAs a bonus, this patch series also contains fixes for the Perl tests (which\nwere broken for a few years, unnoticed because the CI runs need to save on\nruntime and therefore skip the Perl tests because the consume a lot of\ntime).\n\nChanges since v3:\n\n * Re-added the credits to Patrick's research that was accidentally dropped\n   from the commit message of \"t0600: fix incomplete prerequisite for a test\n   case\"\n\nChanges since v2:\n\n * Polished commit messages.\n\nChanges since v1:\n\n * Fixed a grammar issue.\n * Using cmp rather than skipping the comparison (thanks Junio).\n * Extended a commit message to explain that it covers all the cases where\n   core.preferSymlinkRefs needs special care.\n\nJohannes Schindelin (10):\n  t9700: accommodate for Windows paths\n  apply: symbolic links lack a \"trustable executable bit\"\n  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  t0001: handle `diff --no-index` gracefully\n  t0301: another fix for Windows compatibility\n  t0600: fix incomplete prerequisite for a test case\n  t1006: accommodate for symlink support in MSYS2\n  t1305: skip symlink tests that do not apply to Windows\n  t6423: introduce Windows-specific handling for symlinking to /dev/null\n  t7800: work around the MSYS path conversion on Windows\n\n apply.c                             |  2 +-\n compat/mingw.c                      | 14 ++++++++++++++\n t/t0001-init.sh                     |  6 +++++-\n t/t0301-credential-cache.sh         |  3 ++-\n t/t0600-reffiles-backend.sh         |  2 +-\n t/t1006-cat-file.sh                 | 24 +++++++++++++++++-------\n t/t1305-config-include.sh           |  4 ++--\n t/t6423-merge-rename-directories.sh |  9 +++++++--\n t/t7800-difftool.sh                 |  8 ++++----\n t/t9700/test.pl                     |  9 +++++++--\n 10 files changed, 60 insertions(+), 21 deletions(-)\n\n\nbase-commit: 9a2fb147f2c61d0cab52c883e7e26f5b7948e3ed\nPublished-As: https://github.com/gitgitgadget/git/releases/tag/pr-2009%2Fdscho%2Fprepare-the-test-suite-for-symlink-support-on-windows-v4\nFetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-2009/dscho/prepare-the-test-suite-for-symlink-support-on-windows-v4\nPull-Request: https://github.com/gitgitgadget/git/pull/2009\n\nRange-diff vs v3:\n\n  1:  2d329837e3 =  1:  2d329837e3 t9700: accommodate for Windows paths\n  2:  b97afa9a5c =  2:  b97afa9a5c apply: symbolic links lack a \"trustable executable bit\"\n  3:  f42a2f14bc =  3:  f42a2f14bc mingw: special-case `open(symlink, O_CREAT | O_EXCL)`\n  4:  70237394c6 =  4:  70237394c6 t0001: handle `diff --no-index` gracefully\n  5:  0d371ee552 =  5:  0d371ee552 t0301: another fix for Windows compatibility\n  6:  91bd72062c !  6:  7b233c2d40 t0600: fix incomplete prerequisite for a test case\n     @@ Commit message\n          However, the `preferSymlinkRefs` feature is not supported on Windows,\n          therefore this test case needs the `MINGW` prerequisite, too.\n      \n     +    There's a couple more cases where we set this config key:\n     +\n     +      - In a subsequent test in t0600, but there we explicitly set it to\n     +        \"false\". So this would naturally be supported by Windows.\n     +\n     +      - In t7201 we set the value to `yes`, but we never verify that the\n     +        written reference is a symbolic link in the first place. I guess\n     +        that we could rather remove setting the configuration value here, as\n     +        we are about to deprecate support for symrefs via symbolic links in\n     +        the first place. But that's certainly outside of the scope of this\n     +        patch.\n     +\n     +      - In t9903 we do the same, but likewise, we don't check whether the\n     +        written file is a symbolic link.\n     +\n     +    Therefore this seems to be the only instance where the tests actually\n     +    need to be adapted.\n     +\n     +    Helped-by: Patrick Steinhardt <ps@pks.im>\n          Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n      \n       ## t/t0600-reffiles-backend.sh ##\n  7:  c2d3212f11 =  7:  31ed59481c t1006: accommodate for symlink support in MSYS2\n  8:  03ff6d756d =  8:  37f9614ef5 t1305: skip symlink tests that do not apply to Windows\n  9:  4ab6aaf2cf =  9:  e604ace822 t6423: introduce Windows-specific handling for symlinking to /dev/null\n 10:  5f056902df = 10:  6caf8bf0b1 t7800: work around the MSYS path conversion on Windows\n\n-- \ngitgitgadget\n"},{"id":"532352","messageId":"2d329837e34a88cfe28be728fe24bb5a2c6a9752.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 01/10] t9700: accommodate for Windows paths","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:37Z","receivedAt":"2025-12-17T14:18:50Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nEver since fe53bbc9beb (Git.pm: Always set Repository to absolute path\nif autodetecting, 2009-05-07), the t9700 test _must_ fail on Windows\nbecause of that age-old Unix paths vs Windows paths problem.\n\nThe underlying root cause is that Git cannot run with a regular Win32\nvariant of Perl, the assumption that every path is a Unix path is just\ntoo strong in Git's Perl code.\n\nAs a consequence, Git for Windows is basically stuck with using the\nMSYS2 variant of Perl which uses a POSIX emulation layer (which is a\nfriendly fork of Cygwin) _and_ a best-effort Unix <-> Windows paths\nconversion whenever crossing the boundary between MSYS2 and regular\nWin32 processes. It is best effort only, though, using heuristics to\nautomagically convert correctly in most cases, but not in all cases.\n\nIn the context of this here patch, this means that asking `git.exe` for\nthe absolute path of the `.git/` directory will return a Win32 path\nbecause `git.exe` is a regular Win32 executable that has no idea about\nUnix-ish paths. But above-mentioned commit introduced a test that wants\nto verify that this path is identical to the one that the Git Perl\nmodule reports (which refuses to use Win32 paths and uses Unix-ish paths\ninstead). Obviously, this must fail because no heuristics can kick in at\nthat layer.\n\nThis test failure has not even been caught when Git introduced Windows\nsupport in its CI definition in 2e90484eb4a (ci: add a Windows job to\nthe Azure Pipelines definition, 2019-01-29), as all tests relying on\nPerl had to be disabled even from the start (because the CI runs would\notherwise have resulted in prohibitively long runtimes, not because\nWindows is super slow per se, but because Git's test suite keeps\ninsisting on using technology that requires a POSIX emulation layer,\nwhich _is_ super slow on Windows).\n\nTo work around this failure, let's use the `cygpath` utility to convert\nthe absolute `gitdir` path into the form that the Perl code expects.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t9700/test.pl | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t9700/test.pl b/t/t9700/test.pl\nindex 58a9b328d5..570b0c5680 100755\n--- a/t/t9700/test.pl\n+++ b/t/t9700/test.pl\n@@ -117,7 +117,12 @@ close TEMPFILE;\n unlink $tmpfile;\n \n # paths\n-is($r->repo_path, $abs_repo_dir . \"/.git\", \"repo_path\");\n+my $abs_git_dir = $abs_repo_dir . \"/.git\";\n+if ($^O eq 'msys' or $^O eq 'cygwin') {\n+  $abs_git_dir = `cygpath -am \"$abs_repo_dir/.git\"`;\n+  $abs_git_dir =~ s/\\r?\\n?$//;\n+}\n+is($r->repo_path, $abs_git_dir, \"repo_path\");\n is($r->wc_path, $abs_repo_dir . \"/\", \"wc_path\");\n is($r->wc_subdir, \"\", \"wc_subdir initial\");\n $r->wc_chdir(\"directory1\");\n@@ -127,7 +132,7 @@ is($r->config(\"test.string\"), \"value\", \"config after wc_chdir\");\n # Object generation in sub directory\n chdir(\"directory2\");\n my $r2 = Git->repository();\n-is($r2->repo_path, $abs_repo_dir . \"/.git\", \"repo_path (2)\");\n+is($r2->repo_path, $abs_git_dir, \"repo_path (2)\");\n is($r2->wc_path, $abs_repo_dir . \"/\", \"wc_path (2)\");\n is($r2->wc_subdir, \"directory2/\", \"wc_subdir initial (2)\");\n \n-- \ngitgitgadget\n\n"},{"id":"532353","messageId":"b97afa9a5c28aa89fd94f210a0dec5de891eb221.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 02/10] apply: symbolic links lack a \"trustable executable bit\"","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:38Z","receivedAt":"2025-12-17T14:18:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nWhen 0482c32c334b (apply: ignore working tree filemode when\n!core.filemode, 2023-12-26) fixed `git apply` to stop warning about\nexecutable files, it inadvertently changed the code flow also for\nsymbolic links and directories.\n\nLet's narrow the scope of the special `!trust_executable_git` code path\nto apply only to regular files.\n\nThis is needed to let t4115.5(symlink escape when creating new files)\npass on Windows when symbolic link support is enabled in the MSYS2\nruntime.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n apply.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/apply.c b/apply.c\nindex a2ceb3fb40..de5750354a 100644\n--- a/apply.c\n+++ b/apply.c\n@@ -3779,7 +3779,7 @@ static int check_preimage(struct apply_state *state,\n \t\tif (*ce && !(*ce)->ce_mode)\n \t\t\tBUG(\"ce_mode == 0 for path '%s'\", old_name);\n \n-\t\tif (trust_executable_bit)\n+\t\tif (trust_executable_bit || !S_ISREG(st->st_mode))\n \t\t\tst_mode = ce_mode_from_stat(*ce, st->st_mode);\n \t\telse if (*ce)\n \t\t\tst_mode = (*ce)->ce_mode;\n-- \ngitgitgadget\n\n"},{"id":"532354","messageId":"f42a2f14bce6920200e4ee993b76b37d4a762441.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 03/10] mingw: special-case `open(symlink, O_CREAT | O_EXCL)`","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:39Z","receivedAt":"2025-12-17T14:18:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe `_wopen()` function would gladly follow a symbolic link to a\nnon-existent file and create it when given above-mentioned flags.\n\nGit expects the `open()` call to fail, though. So let's add yet another\nwork-around to pretend that Windows behaves according to POSIX, see:\nhttps://pubs.opengroup.org/onlinepubs/007904875/functions/open.html#:~:text=If%20O_CREAT%20and%20O_EXCL%20are,set%2C%20the%20result%20is%20undefined.\n\nThis is required to let t4115.8(--reject removes .rej symlink if it\nexists) pass on Windows when enabling the MSYS2 runtime's symbolic link\nsupport.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n compat/mingw.c | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/compat/mingw.c b/compat/mingw.c\nindex 736a07a028..9fbf12a3d3 100644\n--- a/compat/mingw.c\n+++ b/compat/mingw.c\n@@ -627,6 +627,7 @@ int mingw_open (const char *filename, int oflags, ...)\n \tint fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);\n \twchar_t wfilename[MAX_PATH];\n \topen_fn_t open_fn;\n+\tWIN32_FILE_ATTRIBUTE_DATA fdata;\n \n \tDECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);\n \n@@ -651,6 +652,19 @@ int mingw_open (const char *filename, int oflags, ...)\n \telse if (xutftowcs_path(wfilename, filename) < 0)\n \t\treturn -1;\n \n+\t/*\n+\t * When `symlink` exists and is a symbolic link pointing to a\n+\t * non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would\n+\t * create that file. Not what we want: Linux would say `EEXIST`\n+\t * in that instance, which is therefore what Git expects.\n+\t */\n+\tif (create &&\n+\t    GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&\n+\t    (fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {\n+\t\terrno = EEXIST;\n+\t\treturn -1;\n+\t}\n+\n \tfd = open_fn(wfilename, oflags, mode);\n \n \t/*\n-- \ngitgitgadget\n\n"},{"id":"532355","messageId":"70237394c64101b3d70a1d31bd4a763997474cb1.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 04/10] t0001: handle `diff --no-index` gracefully","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:40Z","receivedAt":"2025-12-17T14:18:54Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe test case 're-init to move gitdir symlink' wants to compare the\ncontents of `newdir/.git`, which is a symbolic link pointing to a file.\nHowever, `git diff --no-index`, which is used by `test_cmp` on Windows,\ndoes not resolve symlinks; It shows the symlink _target_ instead (with a\nfile mode of 120000). That is totally unexpected by the test case, which\nas a consequence fails, meaning that it's a bug in the test case itself.\n\nCo-authored-by: Junio C Hamano <gitster@pobox.com>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0001-init.sh | 6 +++++-\n 1 file changed, 5 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0001-init.sh b/t/t0001-init.sh\nindex 618da080dc..e4d32bb4d2 100755\n--- a/t/t0001-init.sh\n+++ b/t/t0001-init.sh\n@@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '\n \tgit init --separate-git-dir ../realgitdir\n \t) &&\n \techo \"gitdir: $(pwd)/realgitdir\" >expected &&\n-\ttest_cmp expected newdir/.git &&\n+\tcase \"$GIT_TEST_CMP\" in\n+\t# `git diff --no-index` does not resolve symlinks\n+\t*--no-index*) cmp expected newdir/.git;;\n+\t*) test_cmp expected newdir/.git;;\n+\tesac &&\n \ttest_cmp expected newdir/here &&\n \ttest_path_is_dir realgitdir/refs\n '\n-- \ngitgitgadget\n\n"},{"id":"532356","messageId":"0d371ee552a0fd8aaad9e94c3a7477823852d25e.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 05/10] t0301: another fix for Windows compatibility","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:41Z","receivedAt":"2025-12-17T14:18:56Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nJust like 0fdcfa2f9f5 (t0301: fixes for windows compatibility,\n2021-09-14) explained, we should not call `mkdir -m<mode>` in the test\nsuite because that would fail on Windows.\n\nThere was one forgotten instance of this which was hidden by a `SYMLINK`\nprerequisite. Currently, this prevents this test case from being\nexecuted on Windows, but with the upcoming support for symbolic links,\nit would become a problem.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0301-credential-cache.sh | 3 ++-\n 1 file changed, 2 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t0301-credential-cache.sh b/t/t0301-credential-cache.sh\nindex dc30289f75..6f7cfd9e33 100755\n--- a/t/t0301-credential-cache.sh\n+++ b/t/t0301-credential-cache.sh\n@@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to\n \t\trmdir \\\"\\$HOME/dir/\\\" &&\n \t\trm \\\"\\$HOME/.git-credential-cache\\\"\n \t\" &&\n-\tmkdir -p -m 700 \"$HOME/dir/\" &&\n+\tmkdir -p \"$HOME/dir/\" &&\n+\tchmod 700 \"$HOME/dir/\" &&\n \tln -s \"$HOME/dir\" \"$HOME/.git-credential-cache\" &&\n \tcheck approve cache <<-\\EOF &&\n \tprotocol=https\n-- \ngitgitgadget\n\n"},{"id":"532357","messageId":"7b233c2d406d1aa3bc9bfd4d084c6e5dba481b47.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 06/10] t0600: fix incomplete prerequisite for a test case","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:42Z","receivedAt":"2025-12-17T14:18:57Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe 'symref transaction supports symlinks' test case is guarded by the\n`SYMLINK` prerequisite because `core.prefersymlinkrefs = true` requires\nsymbolic links to be supported.\n\nHowever, the `preferSymlinkRefs` feature is not supported on Windows,\ntherefore this test case needs the `MINGW` prerequisite, too.\n\nThere's a couple more cases where we set this config key:\n\n  - In a subsequent test in t0600, but there we explicitly set it to\n    \"false\". So this would naturally be supported by Windows.\n\n  - In t7201 we set the value to `yes`, but we never verify that the\n    written reference is a symbolic link in the first place. I guess\n    that we could rather remove setting the configuration value here, as\n    we are about to deprecate support for symrefs via symbolic links in\n    the first place. But that's certainly outside of the scope of this\n    patch.\n\n  - In t9903 we do the same, but likewise, we don't check whether the\n    written file is a symbolic link.\n\nTherefore this seems to be the only instance where the tests actually\nneed to be adapted.\n\nHelped-by: Patrick Steinhardt <ps@pks.im>\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t0600-reffiles-backend.sh | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\nindex b11126ed47..74bfa2e9ba 100755\n--- a/t/t0600-reffiles-backend.sh\n+++ b/t/t0600-reffiles-backend.sh\n@@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '\n \tesac\n '\n \n-test_expect_success SYMLINKS 'symref transaction supports symlinks' '\n+test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '\n \ttest_when_finished \"git symbolic-ref -d TEST_SYMREF_HEAD\" &&\n \tgit update-ref refs/heads/new @ &&\n \ttest_config core.prefersymlinkrefs true &&\n-- \ngitgitgadget\n\n"},{"id":"532359","messageId":"31ed59481c59727a95868a8473f1fdfe258831cc.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 07/10] t1006: accommodate for symlink support in MSYS2","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:43Z","receivedAt":"2025-12-17T14:18:58Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe MSYS2 runtime (which inherits this trait from the Cygwin runtime,\nand which is used by Git for Windows' Bash to emulate POSIX\nfunctionality on Windows, the same Bash that is also used to run Git's\ntest suite on Windows) has a mode where it can create native symbolic\nlinks on Windows.\n\nNaturally, this is a bit of a strange feature, given that Cygwin goes\nout of its way to support Unix-like paths even if no Win32 program\nunderstands those, and the symbolic links have to use Win32 paths\ninstead (which Win32 programs understand very well).\n\nAs a consequence, the symbolic link targets get normalized before the\nlinks are created.\n\nThis results in certain quirks that Git's test suite is ill equipped to\naccommodate (because Git's test suite expects to be able to use\nUnix-like paths even on Windows).\n\nThe test script t1006-cat-file.sh contains two prime examples, two test\ncases that need to skip a couple assertions because they are simply\nwrong in the context of Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t1006-cat-file.sh | 24 +++++++++++++++++-------\n 1 file changed, 17 insertions(+), 7 deletions(-)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 1f61b666a7..0eee3bb878 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-\n \techo .. >>expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual &&\n-\techo symlink 3 >expect &&\n-\techo ../ >>expect &&\n+\tif test_have_prereq MINGW,SYMLINKS\n+\tthen\n+\t\ttest_write_lines \"symlink 2\" ..\n+\telse\n+\t\ttest_write_lines \"symlink 3\" ../\n+\tfi >expect &&\n \techo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp expect actual\n '\n \n test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '\n-\techo HEAD: | git cat-file --batch-check >expect &&\n-\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n-\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n-\ttest_cmp expect actual &&\n+\tif test_have_prereq !MINGW\n+\tthen\n+\t\t# The `up-down` and `up-down-trailing` symlinks are normalized\n+\t\t# in MSYS in `winsymlinks` mode and are therefore in a\n+\t\t# different shape than Git expects them.\n+\t\techo HEAD: | git cat-file --batch-check >expect &&\n+\t\techo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual &&\n+\t\techo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&\n+\t\ttest_cmp expect actual\n+\tfi &&\n \techo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&\n \ttest_cmp found actual &&\n \techo symlink 7 >expect &&\n-- \ngitgitgadget\n\n"},{"id":"532358","messageId":"37f9614ef5c62ef9619c43acdf9b26e81b99940c.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 08/10] t1305: skip symlink tests that do not apply to Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:44Z","receivedAt":"2025-12-17T14:18:59Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nIn Git for Windows, the gitdir is canonicalized so that even when the\ngitdir is specified via a symbolic link, the `gitdir:` conditional\ninclude will only match the real directory path.\n\nUnfortunately, t1305 codifies a different behavior in two test cases,\nwhich are hereby skipped on Windows.\n\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 8ff2b0c232..6e51f892f3 100755\n--- a/t/t1305-config-include.sh\n+++ b/t/t1305-config-include.sh\n@@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '\n \tln -s foo bar &&\n \t(\n \t\tcd bar &&\n@@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '\n \t)\n '\n \n-test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '\n+test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '\n \t(\n \t\tcd bar &&\n \t\techo \"[includeIf \\\"gitdir/i:BAR/\\\"]path=bar8\" >>.git/config &&\n-- \ngitgitgadget\n\n"},{"id":"532360","messageId":"e604ace822e4f9986a212bbc4e491f2e9f096510.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 09/10] t6423: introduce Windows-specific handling for symlinking to /dev/null","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:45Z","receivedAt":"2025-12-17T14:19:01Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nThe device `/dev/null` does not exist on Windows, it's called `NUL`\nthere. Calling `ln -s /dev/null my-symlink` in a symlink-enabled MSYS2\nBash will therefore literally link to a file or directory called `null`\nthat is supposed to be in the current drive's top-level `dev` directory.\nWhich typically does not exist.\n\nThe test, however, really wants the created symbolic link to point to\nthe NUL device. Let's instead use the `mklink` utility on Windows to\nperform that job, and keep using `ln -s /dev/null <target>` on\nnon-Windows platforms.\n\nWhile at it, add the missing `SYMLINKS` prereq because this test _still_\nwould not pass on Windows before support for symbolic links is\nupstreamed from Git for Windows.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t6423-merge-rename-directories.sh | 9 +++++++--\n 1 file changed, 7 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh\nindex 533ac85dc8..53535a8ebf 100755\n--- a/t/t6423-merge-rename-directories.sh\n+++ b/t/t6423-merge-rename-directories.sh\n@@ -5158,13 +5158,18 @@ test_setup_12m () {\n \t\tgit switch B &&\n \t\tgit rm dir/subdir/file &&\n \t\tmkdir dir &&\n-\t\tln -s /dev/null dir/subdir &&\n+\t\tif test_have_prereq MINGW\n+\t\tthen\n+\t\t\tcmd //c 'mklink dir\\subdir NUL'\n+\t\telse\n+\t\t\tln -s /dev/null dir/subdir\n+\t\tfi &&\n \t\tgit add . &&\n \t\tgit commit -m \"B\"\n \t)\n }\n \n-test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '\n+test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '\n \ttest_setup_12m &&\n \t(\n \t\tcd 12m &&\n-- \ngitgitgadget\n\n"},{"id":"532361","messageId":"6caf8bf0b193f325ac4a3787b5619b8338154298.1765981126.git.gitgitgadget@gmail.com","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"[PATCH v4 10/10] t7800: work around the MSYS path conversion on Windows","fromName":"Johannes Schindelin via GitGitGadget","fromEmail":"gitgitgadget@gmail.com","sentAt":"2025-12-17T14:18:46Z","receivedAt":"2025-12-17T14:19:04Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"From: Johannes Schindelin <johannes.schindelin@gmx.de>\n\nGit's test suite's relies on Unix shell scripting, which is\nunderstandable, of course, given Git's firm roots (and indeed, ongoing\nfocus) on Linux.\n\nThis fact, combined with Unix shell scripting's natural\nhabitat -- which is, naturally... *drumroll*... Unix --\noften has unintended side effects, where developers expect the test\nsuite to run in a Unix environment, which is an incorrect assumption.\n\nOne instance of this problem can be observed in the 'difftool --dir-diff\nhandles modified symlinks' test case in `t7800-difftool.sh`, which\nassumes that all absolute paths start with a forward slash. That\nassumption is incorrect in general, e.g. on Windows, where absolute\npaths have many shapes and forms, none of which starts with a forward\nslash.\n\nThe only saving grace is that this test case is currently not run on\nWindows because of the `SYMLINK` prerequisite. However, I am currently\nworking towards upstreaming symbolic link support from Git for Windows\nto upstream Git, which will put a crack into that saving grace.\n\nLet's change that test case so that it does not rely on absolute paths\n(which are passed to the \"external command\" `ls` as parameters and are\ntherefore part of its output, and which the test case wants to filter\nout before verifying that the output is as expected) starting with a\nforward slash. Let's instead rely on the much more reliable fact that\n`ls` will output the path in a line that ends in a colon, and simply\nfilter out those lines by matching said colon instead.\n\nSigned-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>\n---\n t/t7800-difftool.sh | 8 ++++----\n 1 file changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/t/t7800-difftool.sh b/t/t7800-difftool.sh\nindex 9b74db5563..bf0f67378d 100755\n--- a/t/t7800-difftool.sh\n+++ b/t/t7800-difftool.sh\n@@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \t\tc\n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \t# The left side contains symlink \"c\" that points to \"b\"\n@@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '\n \n \tEOF\n \tgit difftool --symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual &&\n \n \tgit difftool --no-symlinks --dir-diff --extcmd ls >output &&\n-\tgrep -v ^/ output >actual &&\n+\tgrep -v \":\\$\" output >actual &&\n \ttest_cmp expect actual\n '\n \n-- \ngitgitgadget\n"},{"id":"532390","messageId":"xmqq34581ysu.fsf@gitster.g","threadId":"64552","inReplyTo":"pull.2009.v4.git.1765981126.gitgitgadget@gmail.com","subject":"Re: [PATCH v4 00/10] Prepare Git's test suite for symbolic link support on Windows","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-17T23:19:45Z","receivedAt":"2025-12-17T23:19:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\"Johannes Schindelin via GitGitGadget\" <gitgitgadget@gmail.com>\nwrites:\n\n> Changes since v3:\n>\n>  * Re-added the credits to Patrick's research that was accidentally dropped\n>    from the commit message of \"t0600: fix incomplete prerequisite for a test\n>    case\"\n\nThis matched what I expected to see.  Will replace with this\niteration to keep the Message-Ids of the commits straight.\n\nThanks.\n"}]}