Merge branch 'js/test-symlink-windows' into seen

Prepare test suite for Git for Windows that supports symbolic
links.

Comments?
cf. <xmqqms44cb7p.fsf@gitster.g>
cf. <xmqqecpgc8wd.fsf@gitster.g>

* js/test-symlink-windows:
  t7800: work around the MSYS path conversion on Windows
  t6423: introduce Windows-specific handling for symlinking to /dev/null
  t1305: skip symlink tests that do not apply to Windows
  t1006: accommodate for symlink support in MSYS2
  t0600: fix incomplete prerequisite for a test case
  t0301: another fix for Windows compatibility
  t0001: handle `diff --no-index` gracefully
  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`
  apply: symbolic links lack a "trustable executable bit"
  t9700: accommodate for Windows paths
This commit is contained in:
Junio C Hamano
2025-12-12 22:11:53 +09:00
10 changed files with 60 additions and 21 deletions

View File

@@ -3818,7 +3818,7 @@ static int check_preimage(struct apply_state *state,
if (*ce && !(*ce)->ce_mode)
BUG("ce_mode == 0 for path '%s'", old_name);
if (trust_executable_bit)
if (trust_executable_bit || !S_ISREG(st->st_mode))
st_mode = ce_mode_from_stat(*ce, st->st_mode);
else if (*ce)
st_mode = (*ce)->ce_mode;

View File

@@ -629,6 +629,7 @@ int mingw_open (const char *filename, int oflags, ...)
int fd, create = (oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL);
wchar_t wfilename[MAX_PATH];
open_fn_t open_fn;
WIN32_FILE_ATTRIBUTE_DATA fdata;
DECLARE_PROC_ADDR(ntdll.dll, NTSTATUS, NTAPI, RtlGetLastNtStatus, void);
@@ -653,6 +654,19 @@ int mingw_open (const char *filename, int oflags, ...)
else if (xutftowcs_path(wfilename, filename) < 0)
return -1;
/*
* When `symlink` exists and is a symbolic link pointing to a
* non-existing file, `_wopen(symlink, O_CREAT | O_EXCL)` would
* create that file. Not what we want: Linux would say `EEXIST`
* in that instance, which is therefore what Git expects.
*/
if (create &&
GetFileAttributesExW(wfilename, GetFileExInfoStandard, &fdata) &&
(fdata.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
errno = EEXIST;
return -1;
}
fd = open_fn(wfilename, oflags, mode);
/*

View File

@@ -425,7 +425,11 @@ test_expect_success SYMLINKS 're-init to move gitdir symlink' '
git init --separate-git-dir ../realgitdir
) &&
echo "gitdir: $(pwd)/realgitdir" >expected &&
test_cmp expected newdir/.git &&
case "$GIT_TEST_CMP" in
# `git diff --no-index` does not resolve symlinks
*--no-index*) cmp expected newdir/.git;;
*) test_cmp expected newdir/.git;;
esac &&
test_cmp expected newdir/here &&
test_path_is_dir realgitdir/refs
'

View File

@@ -123,7 +123,8 @@ test_expect_success SYMLINKS 'use user socket if user directory is a symlink to
rmdir \"\$HOME/dir/\" &&
rm \"\$HOME/.git-credential-cache\"
" &&
mkdir -p -m 700 "$HOME/dir/" &&
mkdir -p "$HOME/dir/" &&
chmod 700 "$HOME/dir/" &&
ln -s "$HOME/dir" "$HOME/.git-credential-cache" &&
check approve cache <<-\EOF &&
protocol=https

View File

@@ -467,7 +467,7 @@ test_expect_success POSIXPERM 'git reflog expire honors core.sharedRepository' '
esac
'
test_expect_success SYMLINKS 'symref transaction supports symlinks' '
test_expect_success SYMLINKS,!MINGW 'symref transaction supports symlinks' '
test_when_finished "git symbolic-ref -d TEST_SYMREF_HEAD" &&
git update-ref refs/heads/new @ &&
test_config core.prefersymlinkrefs true &&

View File

@@ -1048,18 +1048,28 @@ test_expect_success 'git cat-file --batch-check --follow-symlinks works for out-
echo .. >>expect &&
echo HEAD:dir/subdir/out-of-repo-link-dir | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo symlink 3 >expect &&
echo ../ >>expect &&
if test_have_prereq MINGW,SYMLINKS
then
test_write_lines "symlink 2" ..
else
test_write_lines "symlink 3" ../
fi >expect &&
echo HEAD:dir/subdir/out-of-repo-link-dir-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual
'
test_expect_success 'git cat-file --batch-check --follow-symlinks works for symlinks with internal ..' '
echo HEAD: | git cat-file --batch-check >expect &&
echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
if test_have_prereq !MINGW
then
# The `up-down` and `up-down-trailing` symlinks are normalized
# in MSYS in `winsymlinks` mode and are therefore in a
# different shape than Git expects them.
echo HEAD: | git cat-file --batch-check >expect &&
echo HEAD:up-down | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual &&
echo HEAD:up-down-trailing | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp expect actual
fi &&
echo HEAD:up-down-file | git cat-file --batch-check --follow-symlinks >actual &&
test_cmp found actual &&
echo symlink 7 >expect &&

View File

@@ -286,7 +286,7 @@ test_expect_success SYMLINKS 'conditional include, relative path with symlinks'
)
'
test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink' '
ln -s foo bar &&
(
cd bar &&
@@ -298,7 +298,7 @@ test_expect_success SYMLINKS 'conditional include, gitdir matching symlink' '
)
'
test_expect_success SYMLINKS 'conditional include, gitdir matching symlink, icase' '
test_expect_success SYMLINKS,!MINGW 'conditional include, gitdir matching symlink, icase' '
(
cd bar &&
echo "[includeIf \"gitdir/i:BAR/\"]path=bar8" >>.git/config &&

View File

@@ -5158,13 +5158,18 @@ test_setup_12m () {
git switch B &&
git rm dir/subdir/file &&
mkdir dir &&
ln -s /dev/null dir/subdir &&
if test_have_prereq MINGW
then
cmd //c 'mklink dir\subdir NUL'
else
ln -s /dev/null dir/subdir
fi &&
git add . &&
git commit -m "B"
)
}
test_expect_success '12m: Change parent of renamed-dir to symlink on other side' '
test_expect_success SYMLINKS '12m: Change parent of renamed-dir to symlink on other side' '
test_setup_12m &&
(
cd 12m &&

View File

@@ -752,11 +752,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
c
EOF
git difftool --symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&
git difftool --no-symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&
# The left side contains symlink "c" that points to "b"
@@ -786,11 +786,11 @@ test_expect_success SYMLINKS 'difftool --dir-diff handles modified symlinks' '
EOF
git difftool --symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual &&
git difftool --no-symlinks --dir-diff --extcmd ls >output &&
grep -v ^/ output >actual &&
grep -v ":\$" output >actual &&
test_cmp expect actual
'

View File

@@ -117,7 +117,12 @@ close TEMPFILE;
unlink $tmpfile;
# paths
is($r->repo_path, $abs_repo_dir . "/.git", "repo_path");
my $abs_git_dir = $abs_repo_dir . "/.git";
if ($^O eq 'msys' or $^O eq 'cygwin') {
$abs_git_dir = `cygpath -am "$abs_repo_dir/.git"`;
$abs_git_dir =~ s/\r?\n?$//;
}
is($r->repo_path, $abs_git_dir, "repo_path");
is($r->wc_path, $abs_repo_dir . "/", "wc_path");
is($r->wc_subdir, "", "wc_subdir initial");
$r->wc_chdir("directory1");
@@ -127,7 +132,7 @@ is($r->config("test.string"), "value", "config after wc_chdir");
# Object generation in sub directory
chdir("directory2");
my $r2 = Git->repository();
is($r2->repo_path, $abs_repo_dir . "/.git", "repo_path (2)");
is($r2->repo_path, $abs_git_dir, "repo_path (2)");
is($r2->wc_path, $abs_repo_dir . "/", "wc_path (2)");
is($r2->wc_subdir, "directory2/", "wc_subdir initial (2)");