Open
Description
Setup
- Which version of Git for Windows are you using? Is it 32-bit or 64-bit?
$ git --version --build-options
git version 2.32.0.windows.2
cpu: x86_64
built from commit: 3d45ac813c4adf97fe3733c1f763ab6617d5add5
sizeof-long: 4
sizeof-size_t: 8
shell-path: /bin/sh
feature: fsmonitor--daemon
- Which version of Windows are you running? Vista, 7, 8, 10? Is it 32-bit or 64-bit?
$ cmd.exe /c ver
Microsoft Windows [Version 10.0.19043.1110]
- What options did you set as part of the installation? Or did you choose the
defaults?
# One of the following:
> type "C:\Program Files\Git\etc\install-options.txt"
> type "C:\Program Files (x86)\Git\etc\install-options.txt"
> type "%USERPROFILE%\AppData\Local\Programs\Git\etc\install-options.txt"
$ cat /etc/install-options.txt
Editor Option: VIM
Custom Editor Path:
Default Branch Option:
Path Option: Cmd
SSH Option: OpenSSH
Tortoise Option: false
CURL Option: OpenSSL
CRLF Option: CRLFAlways
Bash Terminal Option: MinTTY
Git Pull Behavior Option: Merge
Use Credential Manager: Core
Performance Tweaks FSCache: Enabled
Enable Symlinks: Enabled
Enable Pseudo Console Support: Disabled
Enable FSMonitor: Disabled
- Any other interesting things about your environment that might be related
to the issue you're seeing?
Not that I'm aware of
Details
- Which terminal/shell are you running Git from? e.g Bash/CMD/PowerShell/other
Bash and CMD
- What commands did you run to trigger this issue? If you can provide a
Minimal, Complete, and Verifiable example
this will help us understand the issue.
@echo off
REM using cmd.exe/as a .bat script:
cd /D %TEMP%
mkdir recursive-delete
cd recursive-delete
git init
mkdir a
cd a
mkdir b
cd b
mklink /D /J a ..
cd %TEMP%/recursive-delete
git clean -fd
- What did you expect to occur after running these commands?
Just the following output:
Removing a/
- What actually happened instead?
A warning appeared beforehand:
warning: could not open directory 'a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/b/a/': Function not implemented
Removing a/
- If the problem was occurring with a specific repository, can you provide the
URL to that repository to help us with testing?
N/A
Metadata
Metadata
Assignees
Labels
No labels
Activity
dscho commentedon Aug 16, 2021
This warning comes from the part of the code that enumerates which files are there, and what their respective status is (tracked, ignored, untracked).
The underlying problem is that the reparse point cannot be resolved due to an infinite recursion. I have this tentative diff locally:
The problem is that
strerror(ELOOP)
prints out an unhelpful "Unknown error" on Windows:I am not quite sure how best to proceed from here. Currently, my favorite solution would involve introducing platform-specific
platform_strerror(int errno)
that can override/extendstrerror()
. While it is my favorite solution, I still find it very inelegant.dscho commentedon Aug 16, 2021
BTW the problem has very little to do with the
git clean
command itself: even agit status
triggers the error.rimrul commentedon Aug 17, 2021
Honestly, the whole concept of mappping
GetLastError()
toerrno
is inelegant in the fact it loses precision. I'm pretty sureFormatMessage()
wouldn't produce "Unknown Error" or "Function not implemented" forERROR_CANT_RESOLVE_FILENAME
.dscho commentedon Aug 17, 2021
Agreed.
Introducing an abstraction layer that does not assume that everything has a POSIX
errno
is not going to be a small project, though:jeffrson commentedon Feb 17, 2022
I have a similar issue when using pnpm (a nodejs package manager) with workspaces - which may be completely different. Can open another issue if needed.
pnpm creates a symlinked structure (junctions on Windows) inside node_modules.
git clean -ffdx .
reports warnings like this:I'm not sure, whether the folder might look like "recursive" - directory enumeration above is not.
However, most notably, "node_modules" is in .gitignore -
git status
is fine, and so I'd thinkgit clean -ffdx
should just remove any junction as soon as it finds one, without traversing.dscho commentedon Mar 10, 2022
That almost looks like a symlink loop, but then it ends in:
In any case, it is an awfully long path. I am just surprised that the error message suggests
ENOSYS
when it probably should beENAMETOOLONG
. I guess The reason for that is that we default toENOSYS
when encountering unknown error conditions.Now, it would be really interesting if you could build Git for Windows, patch
compat/mingw.c
to report the unknown error number (via insertingdefault: error("unknown winerr: %ld", winerr); break;
into that long `switch statement) and then tell us that number, so that we can fix the error message.You could also see whether my tentative
diff
would fix the problem on your side.jakebailey commentedon Apr 11, 2023
I'm working on converting a big monorepo to pnpm and I have intentionally introduced cyclic symlinks (kinda like the above), and now hit this problem with
git clean
where it seems to keep walking down the symlinks in Windows.Is there anything I can try here? Are the diffs provided above still accurate?
jakebailey commentedon Apr 11, 2023
Testing the "tentative diff" (#3358 (comment)), I get:
As expected, it seems.
But, why does git walk down the entire loop? It doesn't behave like this on the same structure in Linux/macOS; the clean properly deletes the directory without recursing. It seems like this patch is just intending to change the error, but as noted in previous replies, it seems like it shouldn't be recursing at all.
jakebailey commentedon Apr 11, 2023
Also, going via WSL2 into the same dir behaves properly; so the symlink information and not recursing seems to work, but not in the windows version of git, it seems.
jakebailey commentedon Apr 12, 2023
I've been digging, and I think I've gotten to the root.
finddata2dirent
checks forIO_REPARSE_TAG_SYMLINK
, but the symlinks created by pnpm areIO_REPARSE_TAG_MOUNT_POINT
. The latter seems to be more commonly associated with git's symlink handling and switching the check makes it match the code inmingw_is_mount_point
exactly.I am not an expert in these syscalls, though, but just this fixes the problem for me:
jakebailey commentedon Apr 12, 2023
I've sent #4383 with a test which shows the behavior change. I'm definitely interested in some expert opinions here.
jeremyd2019 commentedon Feb 6, 2025
I think this may be a regression, because #2268 claims to have fixed this
jeremyd2019 commentedon Feb 7, 2025
Stepped through in the debugger, it does attempt to unlink the junction, but
DeleteFileW
,_wunlink
and_wrmdir
all fail, after_wrmdir
GetLastError is 5.jeremyd2019 commentedon Feb 7, 2025
jeremyd2019 commentedon Feb 7, 2025
I don't know anymore.. the error I saw when I reported #5320 seems to have disappeared without me having changed anything.
As far as the spurious warning, this is coming from
jeremyd2019 commentedon Apr 3, 2025
msys2/msys2-autobuild#108 is back. Could someone please look at this on git-for-windows's side? Personally, I think it makes sense to try to have "what is a symlink" agree between the Cygwin and MINGW pieces of git-for-windows, because Git has a habit of calling shell scripts to do things and those scripts would see symlinks where a builtin implementation would not. But perhaps just some sort of band-aid in dir.c (maybe a flag that cmd_clean can set that says "don't recurse into untracked mountpoints") would be enough for this particular scenario?
jeremyd2019 commentedon Apr 4, 2025
It seems that in some scenarios, git clean hangs rather than warning or failing in the face of recursive junctions. msys2/msys2-autobuild#110
[-]Recusive Directory Junctions causes `git clean -fd` to return a warning[/-][+]Recursive Directory Junctions causes `git clean -fd` to return a warning[/+]