Reputation: 155
When I run the WSL bash shell, I can use the "ln -s" command to create a symlink. No matter if I am working on an NTFS file system or on the WSL file system, the symbolic link gets created as expected. Specifically, the link in the WSL file system works just like a Linux symlink and the symlink in the NTFS file system is a Windows symlink and I can use it both from WSL and Windows.
Contrast that to how symlinks work in the Linux version of git running in WSL. I clone a repo that contains symlinks to the NTFS file system. I am not sure what the links are, but they are most definitely not Windows symlinks.
Some might say that I should use the Git for Windows which creates the proper Windows symlink when I clone the repo. The only issue is that we have tools written as bash scripts that everyone uses and these tools call git. They work fine on Linux but from WSL they do not perform as expected because of the symlink issue. I have found that I need all the command-line developer tools to run in WSL so that they can call each other and pass file paths and env vars and such. So it is really not an option for me to run Git for Windows.
Is there any means to get this addressed? If the WSL bash shell can function properly then surely a small change in the Linux version of git could also fix this issue. This smells of some sort of philosophical fight between Windows and Linux. Or is there a legacy to this that pre-dates Git for Windows... In which case, surely there is a way to enable a new treatment of symlinks for those who want to use Windows symlinks.
Upvotes: 3
Views: 1662
Reputation: 76409
This is likely an issue in Windows and the Windows Subsystem for Linux.
The emulated Linux environment creates symlinks using the symlink(2)
system call, much like the ln -s
command does.
The reason this is tricky to support is because Windows symlinks are less capable than Unix symlinks. Unix symlinks can point to any location, regardless of the object at that location, and the destination need not exist. Windows symlinks, on the other hand, point to either a file or a directory, but are pinned to one type.
The standard Git, as shipped by upstream, checks to see if symlinks can be created pointing to a file that does not exist. That this works is important because Git need not check out the destination file before the symlink. If this fails, Git sets core.symlinks
to false, and what's written instead are files with the contents of the symlinks. WSL can't create a symlink of the right type when this test occurs (because there's no destination), and consequently, the operation fails.
Git for Windows likely has some functionality to work around this issue with symlinks in Windows. It also has a huge number of patches which are not included in the version shipped by upstream, and hence not the version used by most Linux distros.
I should point out that there's a Linux distro that also shipped a patch that permitted symlinks to be created only if they pointed to a file the user (and not anyone else) owned, and it broke things in the same way.
You can try to run git config core.symlinks true
in a fresh repository and see if that works as you expect; it may, or it may not. If it doesn't, you can see if the Git for Windows maintainer will send the patch they're using upstream, and it may eventually be included in a newer version of Git, and hence in a newer version of Linux distros. However, because Linux distros typically provide stable versions, this will take time, usually on the order of years, unless you pull down a newer package.
In general, though, you can't expect Unix code to work adequately on an NTFS file system because it's fundamentally different, and Microsoft even documents this behavior. Microsoft knew (or should have known) when they added symlinks how Unix symlinks functioned, and for some reason they chose to do it differently. I personally think that was a mistake, and here we are now.
Upvotes: 4