Josh Kelley
© 2008-2018. All rights reserved. Code under CC-BY 4.0.
Symlinks in Windows, MinGW, Git, and Cygwin
Symlinks are a commonly used feature in Linux and macOS, but Windows traditionally either hasn’t supported them (prior to Windows Vista) or has strictly limited their use. As a result, many cross-platform development tools, like Git for Windows, either didn’t support or didn’t enable symlink support on Windows.
All of this makes cross-platform development on Windows trickier. Fortunately, symlink support on current Windows is mature and functional. You do, however, have to jump through several extra hoops to make it work.
Configuring Windows
Make sure you’re running Windows 10 Creators Update or above. This is the first version to give the option of allowing users to create symlinks without needing UAC elevation. (Prior to that, any processes that needed to manipulate symlinks needed to be run as administrator; this extra step is both annoying and hurts security.)
Enable developer mode: Go under Settings, under Update & Security, under For developers, and set “Use developer features” to “Developer mode.” This is how you enable the Windows 10 Creators Update option of allowing users to create symlinks without UAC elevation.
As described in the Git for Windows documentation, you’ll also need to edit Windows’ local security policy to grant permissions to create symlinks. My personal preference is to use gpedit.msc, since that’s a standard Windows tool. It’s not installed with Home editions of Windows, but, as explained on AskVG, you can install it yourself using these commands.
dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~3*.mum >Files.txt dir /b C:\Windows\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~3*.mum >>Files.txt for /f %i in ('findstr /i . Files.txt 2^>nul') do dism /online /norestart /add-package:"C:\Windows\servicing\Packages\%i" del Files.txt
Incidentally, in case you’re wondering why all of this is necessary, the concern was that symlinks could be a security risk:
Symbolic links (symlinks) can expose security vulnerabilities in applications that aren’t designed to handle symbolic links. — Microsoft TechNet
Although more than a little hand-wavy, this argument is not without merit. Even on Unix-like operating systems, which have had decades to get used to symlinks, the occasional symlink race vulnerability pops up, and Windows software had been developed with no experience or expectation of this feature.
Configuring MinGW, Cygwin, and Git
Now you need to configure your software to make use of Windows’ new features.
For MSYS / MinGW (this includes the command-line utilities that used in the git-bash shell), add an environment variable, MSYS , and make sure it contains winsymlinks:nativestrict . (If you don’t do this, then symlinks are “emulated” by copying files and directories. This can be surprising, to say the least.)
For Cygwin, add an environment variable, CYGWIN , and make sure it contains winsymlinks:nativestrict . See the Cygwin manual for details. (If you don’t do this, then Cygwin defaults to emulating symlinks by using special file contents that it understands but non-Cygwin software doesn’t.)
For Git for Windows, make sure that the core.symlinks config option is true. In a normal Git system, this would be done at the system level ( git config —system core.symlinks true ). However, Git for Windows adds an additional “super-system” configuration file, c:\\ProgramData\\Git\\config ; this was where I had to update core.symlinks on my system. (This Stack Overflow answer describes c:\\ProgramData\\Git\\config better.)
For Subversion, you’re out of luck. Even though Windows supports symlinks, the Subversion libraries don’t have the necessary code to take advantage of this.
Is there any other relevant software that needs configuration to support Windows symlinks? Let me know on Twitter.
Update: If you’re looking for a Windows GUI to help you manage all of these symlinks, the Link Shell Extension is very useful. It allows you to create symlinks, junction points, and more by right-dragging items in Explorer.
Does Windows recognize Linux’s symbolic links?
I was just wondering how a Windows system handles symbolic links (when created via Linux’s ln -s on a filesystem that Windows natively supports and that supports symbolic links, such as NTFS). My best guess is that it will not recognize them, but I’m not entirely sure. Also, what do Macs do when confronted by one?
How do you plan to expose Windows to a symbolic link? It doesn’t understand filesystems that support them (except NTFS, which has something not entirely unlike symbolic links that is mostly hidden from the UI).
Oh.. so what happens if you’ve mounted your Windows partition, and you try to put a symbolic link in it? Does it just work as if it were a folder? (If so, I wonder what happens with RECURSION. )
2 Answers 2
Depends on the Windows version and the configuration of the server-side when we talk about non-local disks.
Since Windows Vista, Windows does have an idea of symbolic links, but the semantics differ. But the more important problem here should be the path names, which follow a different syntax. For starters: single-rooted directory tree on the unixoid side and several drive letters as roots on the Windows side.
On the unixoid side symlinks are merely text files with a special flag. On the Windows side the underlying mechanism is called a reparse point. This tells the object manager to to pass it to particular registered filters (the meta-date for this is stored in the reparse points). Windows 2000 already introduced one type of reparse points known as junction points (roughly, but not quite, directory symlinks). With Vista they introduced symlinks to both files and directories, also on remote drives. And symlinks on remote drives are also supported to some extent.
The main point is whether the file system driver — when run locally — would do any adjustments to the paths Windows gets to see. In such a case it would work for certain local/relative symlinks. For absolute paths as targets things will get difficult and impossible to deduce what’s meant. Same for remote symlinks links (to «network shares»).
As for the Mac side I have no idea and it might make sense as a separate question. But as long as the server side conveys the information that this is a symlink, I see no problems, since they both follow the SUS semantics (unlike Windows).
Consider the Linux side mount points:
/dev/sda1 / /dev/sda2 /home /dev/sda3 /var
And now consider a symlink /home/paul/fstab pointing to /etc/fstab . They are located on two different volumes which Windows — if able to see them through a file system driver (which does work!) — can’t tell belong together the way /etc/fstab describes it. So the link, which Windows would see under a folder \paul\fstab , even if translated, would point to \etc\fstab , which doesn’t exist on /dev/sda2 . And if that symlink would point to the relative path ../../etc/fstab things wouldn’t change at all.
The gist: So while this is conceivable that you can get this to work for some corner cases, the fact that semantics and syntax differ on both sides of the fence makes it unlikely that you will find a practical and generic method that works.
WSL: Using A WSL symlink folder from Windows
I use WSL almost exclusively, and only switch to main windows for browsing and running Windows native programs. I have a git repository located at /mnt/c/myrepo . In order to «install» the code inside /mnt/c/myrepo I need to move it to /mnt/c/otherlocation/renamed . Instead of executing cp -r /mnt/c/myrepo /mnt/c/otherlocation/renamed every time I do a git pull from /mnt/c/myrepo , I would like to symlink /mnt/c/myrepo to /mnt/c/otherlocation/renamed . However when I do this, the program which consumes /mnt/c/otherlocation/renamed isn’t able to view the «contents» of renamed as a directory. I have been all over the WSL github repo and issue tracker trying to find a solution to this issue. I see a lot of exclamations about how symlinks «just work». I have enabled every Windows 10 developer feature I can find, I even followed some reddit thread where someone claimed that purchasing Pengwin and creating a symlink from Pengwin would ensure this compatibility, but I still can’t seem to make this work. The basic usage I need, is allow me to view «renamed» as a directory from windows, or for windows to recognize the symlink as a symlinked directory. from wsl:
ln -s /mnt/c/myrepo /mnt/c/otherlocation/renamed
- open file explorer
- navigate to c:\otherlocation
- open mydir and view the contents as if it were a native directory
Apparently, the correct answer is that the symlink path must be relative. From otherlocation the command is ln -s ../myrepo ./renamed
Using relative paths doesn’t work for me either, also, I have this issue in WSL/Windows 11 but not in WSL/Windows 10