How to make a symlink in the Windows Command Prompt with the mklink
command
Git Bash shell fails to create symbolic links
In Git Bash in Windows, even if ln -s
"succeeds", it doesn't actually create a symlink! Rather, it just copies the entire target! That's lame.
So, to make a symlink in Windows, you have to use the mklink
command in the Windows Command Prompt (cmd.exe
), as an admin, or with "Developer Mode" turned on (see my step 1 in my question here to turn on Developer Mode), like this:
- Press the Windows key --> search for "Command Prompt" --> right-click it and go to "Run as administrator".
- Create symlinks:
# view the help menu
mklink
# Absolute symlinks
# Make a symlink to a **directory** in Windows
mklink /d my_windows_symlink_to_a_dir "C:\path\to\some\target\dir"
# Make a symlink to a **file** in Windows
mklink my_windows_symlink_to_a_file "C:\path\to\some\target\file"
# Relative symlinks
# Make a symlink to a **directory** in Windows
mklink /d my_windows_symlink_to_a_dir "..\..\path\to\some\target\dir"
# Make a symlink to a **file** in Windows
mklink my_windows_symlink_to_a_file "..\..\path\to\some\target\file"
From the Git for Windows community wiki: https://github.com/git-for-windows/git/wiki/symbolic-links:
Creating symbolic links
By default, the ln -s
command in Git Bash does not create symbolic links. Instead, it creates copies.
To create symbolic links (provided your account has permission to do so), use the built-in mklink
command, like so:
mklink /d this-link-points-to c:\that-directory
mklink this-link-points-to c:\that-file
Remember that you must run the mklink
command from the Windows Command Prompt (cmd.exe
), not from the Power Shell! From the Power Shell you'll get this error:
> mklink
mklink : The term 'mklink' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ mklink
+ ~~~~~~
+ CategoryInfo : ObjectNotFound: (mklink:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
But if you type mklink
in the Command Prompt, you'll get this help menu:
C:\WINDOWS\system32>mklink
Creates a symbolic link.
MKLINK [[/D] | [/H] | [/J]] Link Target
/D Creates a directory symbolic link. Default is a file
symbolic link.
/H Creates a hard link instead of a symbolic link.
/J Creates a Directory Junction.
Link Specifies the new symbolic link name.
Target Specifies the path (relative or absolute) that the new link
refers to.
C:\WINDOWS\system32>
A note about committing symlinks to git
, and sharing them between Linux and Windows
If you create and commit a symlink (which points to ../some_dir
) in your repo on Linux with:
ln -si ../some_dir some_dir
and then pull that change down to your repo on Windows, this symlink will just show up as a plain text file named some_dir
and with the text ../some_dir
stored in it.
To fix this broken symlink on Windows, run the following in a Command Prompt as an administrator (not in PowerShell nor Git Bash):
# Delete this Windows symlink directory if it exists and you need to recreate
# and fix it.
rmdir some_dir
# Delete the Linux symlink file which was cloned to Windows as a plain text
# file.
del some_dir
# Now make the Windows symlink
mklink /d some_dir "..\some_dir"
Now, the symlink is recreated and fixed in Windows! git status
will not show this as a change to be committed, because apparently it is syntactically equivalent to the already-committed Linux symlink.
So, if someone clones this repo on Linux (which has the Linux-created symlinks committed to it), their symlinks are all intact and fine.
If someone clones this repo on Windows, however, they must use the Command Prompt as an administrator to manually delete and recreate all symlinks. This can instead be done via a batch script on Windows (learn how to write one, here) to make this easy. Just commit the batch script and instruct Windows users to right-click it and choose "Run as administrator" after cloning the repo in order to repair all symlinks in the repo on Windows. Here is an example batch script that can be committed to the Linux/Windows shared repo and run on Windows:
fix_windows_symlinks.bat Windows batch script to fix symlinks on Windows (reminder: comments begin with ::
or rem
):
:: Delete the Linux symlinks, and replace them with Windows ones.
:: (Fix or make required symlinks on Windows)
:: - This script must be run as an administrator! Right-click it and go to "Run
:: as administrator".
:: get the path to this dir; see: https://mcmap.net/q/49001/-how-to-get-the-path-of-the-batch-script-in-windows
SET SCRIPT_DIRECTORY=%~dp0
cd "%SCRIPT_DIRECTORY:~0,-1%"
:: 1. Delete any directory by this name. This also removes a Windows symlink
:: directory by this name if it exists.
:: - Run this *before* running the `del` cmd below, because the `del` command
:: accidentally used on a **directory** instead of a **file** will ask for a
:: strange "Are you sure (Y/N)?" confirmation instead of just failing. So,
:: instead, first remove the **directory** by this name using `rmdir`,
:: and *then* try to delete a file by this name using `del`, below.
rmdir some_dir
:: 2. Delete any file by this name. This could include the Linux symlink file
:: which was cloned to Windows as a plain text file.
:: - The `del` command will fail normally and without issue if such a file does
:: not exist. It will ask a strange "Are you sure (Y/N)?" confirmation if you
:: accidentally use `del` on a **directory** or symlink to a directory,
:: however, instead of on a **file**.
del some_dir
:: 3. Now make the fixed Windows symlink
mklink /d some_dir "..\some_dir"
:: Another example
rmdir another_dir
del another_dir
mklink /d another_dir "..\..\..\some\other\path\another_dir"
echo "Done!"
PAUSE
In this way, you can easily share repos between Windows and Linux users, even when they rely on relative or absolute symlinks in the repo for your build system, and even when these symlinks may vary between Linux and Windows.
References:
Where I relearned about Windows symbolic links: https://github.com/git-for-windows/git/wiki/symbolic-links
Where I learned how to make a Windows batch script: https://www.howtogeek.com/263177/how-to-write-a-batch-script-on-windows/
Where I learned how to remove a directory in Windows, or a symlink to a directory in Windows: https://www.computerhope.com/mklink.htm#:~:text=To%20delete%20a%20symbolic%20link,link%20use%20the%20del%20command.
Emphasis added:
How do I delete a symbolic link?
To delete a symbolic link, treat it like any other directory or file. If you created a symbolic link using the command shown above, move to the root directory since it is "\Docs" and use the rmdir
command [for symlinks to directories]. If you created a symbolic link (<SYMLINK>
) of a file, to delete a symbolic link use the del
command [for symlinks to files].
Where I learned how to get a path to a batch script in Windows: How to get the path of the batch script in Windows?
I just learned that accidentally using del
on a directory or symlink to a directory will try to delete all contents of the directory, rather than the symlink (to the directory) itself! Watch out! See: How can I delete a symbolic link in Windows?:
Be very careful.
If you have a symbolic link that is a directory (made with mklink /d
) then using del
will delete all of the files in the target directory (the directory that the link points to), rather than just the link.
SOLUTION: rmdir
on the other hand will only delete the directory link, not what the link points to.
ln
aren't really backwards since it supports multiple parameters, you can just list a bunch of files and a directory as a destination and it will work :) Also, with the normal order it is similar tocp
andmv
which is less confusing. – Hydatid