Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git Bash Shell fails to create symbolic links

Tags:

msysgit

msys

When I try to create a symbolic link from the Git Bash shell, it fails every time all the time:

$ ln -s /c/Users/bzisad0/Work testlink ln: creating symbolic link `testlink' to `/c/Users/bzisad0/Work': Permission denied 

The only thing it does, besides give the error message, is create an empty directory named (in this case) testlink.

I don't see any problem with the ln executable. For instance, it is owned by me and marked as executable:

$ which ln /bin/ln  $ ls -hal /bin/ln -rwxr-xr-x    1 BZISAD0  Administ      71k Sep  5 11:55 /bin/ln 

I also own the current directory (~, which is /c/Users/bzisad0):

$ ls -dhal . drwxr-xr-x  115 BZISAD0  Administ      40k Sep  5 12:23 . 

I have administrative rights, and I've tried opening the Git Bash shell with "Run as Administrator", but that makes no difference.

I've tried opening the Windows properties for ln.exe and setting the Privilege Level to "Run this program as an administrator" but that doesn't help.

I've gone into the Security -> Advanced properties in Windows and made myself (rather than the Administrators group) the owner, but that doesn't fix anything either.

I'm at a loss. I don't know whether this error message is ultimately coming from ln, from Bash, or from Windows, or how I could possibly lack the permission. How can I get to the bottom of this?

like image 882
iconoclast Avatar asked Sep 05 '13 16:09

iconoclast


People also ask

How do you create a symbolic link in Shell?

To create a symbolic link, use the -s ( --symbolic ) option. If both the FILE and LINK are given, ln will create a link from the file specified as the first argument ( FILE ) to the file specified as the second argument ( LINK ).

How do I link a file in Git bash?

That is, run Git Bash as admin, run the command export MSYS=winsymlinks:nativestrict , then run ln -s oldFile newLink to your hearts content within that session.

How do I manually create a symbolic link?

Creating symlinks in Windows is pretty easy with the mklink command. To start, press Win + X , then select the option “Command Prompt (Admin)” to open the Command Prompt with admin rights. Once the command prompt has been opened, use the below command format to create a symlink for a file.


1 Answers

It is possible, albeit extremely awkward, to create a symlink in MSYSGIT.

First, we need to make sure we are on Windows. Here's an example function to check that:

windows() { [[ -n "$WINDIR" ]]; } 

Now, we can't do cmd /C, because MSYSGIT will fornicate with this argument and turn it into C:. Also, don't be tempted to use /K, it only works if you don't have a K: drive.

So while it will replace this value on program arguments, it won't on heredocs. We can use this to our advantage:

if windows; then     cmd <<< "mklink /D \"${link%/}\" \"${target%/}\"" > /dev/null else     ln -s "$target" "$link" fi 

Also: note that I included /D because I'm interested in directory symlinks only; Windows has that distinction. With plenty of effort, you could write a ln() { ... } function that wraps the Windows API and serves as a complete drop-in solution, but that's... left as an exercise for the reader.


Edit: As a thank-you for the accepted answer, here's a more comprehensive function.

# We still need this. windows() { [[ -n "$WINDIR" ]]; }  # Cross-platform symlink function. With one parameter, it will check # whether the parameter is a symlink. With two parameters, it will create # a symlink to a file or directory, with syntax: link $linkname $target link() {     if [[ -z "$2" ]]; then         # Link-checking mode.         if windows; then             fsutil reparsepoint query "$1" > /dev/null         else             [[ -h "$1" ]]         fi     else         # Link-creation mode.         if windows; then             # Windows needs to be told if it's a directory or not. Infer that.             # Also: note that we convert `/` to `\`. In this case it's necessary.             if [[ -d "$2" ]]; then                 cmd <<< "mklink /D \"$1\" \"${2//\//\\}\"" > /dev/null             else                 cmd <<< "mklink \"$1\" \"${2//\//\\}\"" > /dev/null             fi         else             # You know what? I think ln's parameters are backwards.             ln -s "$2" "$1"         fi     fi } 

Also note a few things:

  1. I just wrote this and briefly tested it on Win7 and Ubuntu, give it a try first if you're from 2015 and using Windows 9.
  2. NTFS has reparse points and junction points. I chose reparse points because it's more of an actual symlink and works for files or directories, but junction points would have the benefit of being an usable solution in XP, except it's just for directories.
  3. Some filesystems, the FAT ones in particular, do not support symlinks. Modern Windows versions do not support booting from them anymore, but Windows and Linux can mount them.

Bonus function: remove a link.

# Remove a link, cross-platform. rmlink() {     if windows; then         # Again, Windows needs to be told if it's a file or directory.         if [[ -d "$1" ]]; then             rmdir "$1";         else             rm "$1"         fi     else         rm "$1"     fi } 
like image 123
Camilo Martin Avatar answered Sep 20 '22 02:09

Camilo Martin