Git Bash Shell не может создать символические ссылки

Когда я пытаюсь создать символическую ссылку из оболочки Git Bash, она каждый раз терпит неудачу:

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

Единственное, что он делает, кроме сообщения об ошибке, это создает пустой каталог с именем (в данном случае). testlink,

Я не вижу никаких проблем с ln исполняемый файл. Например, он принадлежит мне и помечен как исполняемый:

$ which ln
/bin/ln

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

У меня тоже есть текущий каталог (~, который /c/Users/bzisad0):

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

У меня есть права администратора, и я попытался открыть оболочку Git Bash с помощью "Запуск от имени администратора", но это не имеет значения.

Я пытался открыть свойства Windows для ln.exe и установка уровня привилегий "Запускать эту программу от имени администратора", но это не помогает.

Я вошел в Security -> Advanced properties в Windows и сделал себя (а не группу администраторов) владельцем, но это тоже ничего не исправляет.

Я в недоумении. Я не знаю, приходит ли это сообщение об ошибке в конечном итоге от ln, из Bash, или из Windows, или как я мог не иметь разрешения. Как я могу добраться до сути этого?

12 ответов

Решение

Можно, хотя и крайне неудобно, создать символическую ссылку в MSYSGIT.

Во-первых, нам нужно убедиться, что мы находимся на Windows. Вот пример функции, чтобы проверить это:

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

Теперь мы не можем сделать cmd /Cпотому что MSYSGIT прелюбодействует этим аргументом и превращает его в C:, Кроме того, не поддавайтесь искушению использовать /K, это работает только если у вас нет K: привод.

Таким образом, хотя оно будет заменять это значение на аргументы программы, оно не будет использоваться на heredocs. Мы можем использовать это в наших интересах:

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

Также: обратите внимание, что я включил /D потому что меня интересуют только символические ссылки на каталоги; У Windows есть это различие. Приложив много усилий, вы могли бы написать ln() { ... } функция, которая оборачивает Windows API и служит полным выпадающим решением, но это... оставлено в качестве упражнения для читателя.


Изменить: В качестве благодарности за принятый ответ, вот более полная функция.

# 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
}

Также обратите внимание на несколько вещей:

  1. Я только что написал это и кратко протестировал на Win7 и Ubuntu, сначала попробуйте, если вы из 2015 года и используете Windows 9.
  2. NTFS имеет точки повторного анализа и точки соединения. Я выбрал точки повторной обработки, потому что это скорее символическая ссылка и работает для файлов или каталогов, но точки соединения могут быть полезны в качестве удобного решения в XP, за исключением того, что оно предназначено только для каталогов.
  3. Некоторые файловые системы, в частности, FAT, не поддерживают символические ссылки. Современные версии Windows больше не поддерживают загрузку с них, но Windows и Linux могут их монтировать.

Бонусная функция: удалить ссылку.

# 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
}

Для моей установки это Git для Windows 2.11.0, установленный в Windows 8.1 export MSYS=winsymlinks:nativestrict делает трюк, как описано здесь: https://github.com/git-for-windows/git/pull/156 Важно запускать оболочку Git Bash от имени администратора, поскольку в Windows только администраторы могут создавать символические ссылки. Итак, чтобы сделать tar -xf работаем и создаем необходимые символические ссылки:

  1. Запустите Git Bash shell от имени администратора
  2. Бежать export MSYS=winsymlinks:nativestrict
  3. Запустить смолу

Обходной путь должен бежать mklink из Баш. Это также позволяет вам создать символическую ссылку или соединение.

Позаботьтесь, чтобы отправить mklink команда в качестве единственного аргумента cmd...

cmd  /c "mklink link target"

Вот варианты для mklink...

$ cmd /c 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.

Если вы хотите вместо этого создавать ссылки через графический интерфейс... Я рекомендую Link Shell Extension, которая является плагином Windows Explorer для создания символических ссылок, жестких ссылок, переходов и точек монтирования тома. Я использую это в течение многих лет!

Симлинки могут быть спасением жизни, если у вас на диске C: меньше SSD-накопитель, и вам нужно символически связать некоторые раздутые папки, которые не обязательно должны быть на SSD, с другими дисками. Я использую бесплатный WinDirStat, чтобы найти место на диске.

Я считаю, что ln тот, что поставляется с msysGit, просто пытается скопировать его аргументы, а не возиться со ссылками. Это связано с тем, что ссылки работают (вроде) на файловых системах NTFS, и команда MSYS не хотела переопределять ln.

См., Например, http://mingw.5.n7.nabble.com/symbolic-link-to-My-Documents-in-MSYS-td28492.html

Делать

Предоставьте себе привилегии создавать символические ссылки .

  1. Искать local security policies
  2. Local Policies/User Rights Assignment/Create symbolic links
  3. Найдите минутку, чтобы поругать Windows. «Плохая ОС! Плохая!»
  4. Выгода

Это дает вам право создавать символические ссылки. Обратите внимание: это вступит в силу при следующем входе в систему.

Следующий шаг - выяснить, как настроен

      env | grep MSYS

Мы ищем MSYS=winsymlink: который контролирует, как ln создает символические ссылки.

Если переменная не существует, создайте ее. Обратите внимание: это перезапишет существующую переменную среды MSYS.

      setx MSYS winsymlinks:nativestrict

Не

Запустите оболочку от имени администратора только для создания символических ссылок.

Объяснение

Ошибка очевидна, но неуловима.

У вас нет соответствующих привилегий для выполнения команды.

Почему?

По умолчанию Windows предоставляет администраторам только права на создание символьных ссылок?

должен CYGWINпеть и танцевать, чтобы обойти неадекватную обработку символических ссылок в Windows.

Почему?

Что-то, что-то "сектантство"

¯\_(ツ)_/¯

Редактировать:

Я только что понял, что у OP есть права администратора. Я оставляю этот ответ, надеясь, что он будет полезен другим.

Расширение anwser Камило Мартина, так как вам нужно использовать переключатель параметра /j для Windows 10; в противном случае вызов просто вернет "У вас недостаточно прав для выполнения этой операции".

Это работает для git bash 2.20.1.windows.1/MINGW64 (Windows 10) без прав администратора (если вы можете читать / писать как / old / path, так и /link/path:

original_folder=$(cygpath -w "/old/path")
create_link_new_folder=$(cygpath -w "/link/path")
cmd <<< "mklink /j \"${create_link_new_folder}\" \"${original_folder}\"" > /dev/null

Для всех, кто интересуется, как это сделать в Windows 10 Git Bash 2.28.0.0.1, вы должны указать префикс ln -s команда с MSYS=.. вместо выполнения export MSYS=.. Во-первых, это всего лишь одна команда:

 MSYS=winsymlinks:nativestrict ln -s <TARGET> <NEW_LINK_NAME>

Поскольку это одна из главных ссылок, которые появляются при поиске создания символических ссылок в Msys или git bash, я обнаружил, что ответ заключается в добавленииset MSYS=winsymlinks:native при звонке git-cmd.exe (Я запускаю ConEmu) или раскомментируйте ту же строку в msys2_shell.bat

Я предпочитаю Powershell CMD и решил поделиться версией PowerShell.

В моем случае это состоит из создания символических ссылок, связывающих файл ~/.$ с ~/dotfiles/$file, для конфигурации dotfile. Я положил это внутрь .sh скрипт и запустил его с помощью git-bash:

powershell New-Item -ItemType SymbolicLink\
    -Path \$Home/.$file\
    -Target \$Home/dotfiles/$file

Как создать символическую ссылку в командной строке Windows с помощью команды

Оболочка Git Bash не может создавать символические ссылки

В Git Bash в Windows, даже если «успех», символическая ссылка на самом деле не создается! Скорее, он просто копирует цель целиком! Это глупо.

Итак, чтобы создать символическую ссылку в Windows, вам нужно использовать команду в командной строке Windows () от имени администратора , например:

  1. Нажмите Windowsклавишу -> найдите «Командную строку» -> щелкните ее правой кнопкой мыши и выберите «Запуск от имени администратора».
  2. Создайте символические ссылки:
            # 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"
    

Из вики-сообщества Git для Windows: https://github.com/git-for-windows/git/wiki/symbolic-linkshttps://github.com/git-for-windows/git/wiki/symbolic-links:

Создание символических ссылок

По умолчаниюln -sКоманда в Git Bash не создает символические ссылки. Вместо этого он создает копии.

Чтобы создать символические ссылки (при условии, что у вашей учетной записи есть на это разрешение), используйте встроенную команду, например:

       mklink /d this-link-points-to c:\that-directory
mklink this-link-points-to c:\that-file

Помните, что вы должны запустить команду из командной строки Windows ( cmd.exe) , а не из Power Shell! Из Power Shell вы получите эту ошибку:

      > 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

Но если вы наберетеmklinkв командной строке вы увидите следующее меню справки:

      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>

Примечание о фиксации символических ссылок вgitи обмениваться ими между Linux и Windows

Если вы создадите и зафиксируете символическую ссылку (которая указывает на ) в своем репозитории в Linux с помощью:

      ln -si ../some_dir some_dir

а затем перенесите это изменение в свой репозиторий в Windows, эта символическая ссылка просто отобразится как обычный текстовый файл с именемsome_dirи с текстом../some_dirхранится в нем.

Чтобы исправить эту неработающую символическую ссылку в Windows, выполните следующую команду в командной строке от имени администратора ( не в PowerShell или 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"

Теперь символическая ссылка воссоздана и исправлена ​​в Windows!git statusне будет показывать это как изменение, которое необходимо зафиксировать, поскольку, очевидно, оно синтаксически эквивалентно уже зафиксированной символической ссылке Linux.

Итак, если кто-то клонирует этот репозиторий в Linux (в котором есть созданные Linux символические ссылки), все их символические ссылки останутся неповрежденными и в порядке.

Однако если кто-то клонирует этот репозиторий в Windows, он должен использовать командную строку от имени администратора, чтобы вручную удалить и заново создать все символические ссылки . Вместо этого это можно сделать с помощью пакетного сценария в Windows (узнайте, как его написать, здесьhttps://www.howtogeek.com/263177/how-to-write-a-batch-script-on-windows/ ), чтобы упростить задачу. Просто зафиксируйте пакетный сценарий и попросите пользователей Windows щелкнуть его правой кнопкой мыши и выбрать «Запуск от имени администратора» после клонирования репозитория, чтобы восстановить все символические ссылки в репо в Windows. Вот пример пакетного сценария, который можно зафиксировать в общем репозитории Linux/Windows и запустить в Windows:

fix_windows_symlinks.bat Пакетный скрипт Windows для исправления символических ссылок в Windows (напоминание: комментарии начинаются с::или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://stackoverflow.com/a/3827582/4561887
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

Таким образом, вы можете легко обмениваться репозиториями между пользователями Windows и Linux, даже если они полагаются на относительные или абсолютные символические ссылки в репозитории вашей системы сборки, и даже если эти символические ссылки могут различаться в Linux и Windows.

Использованная литература:

  1. Где я заново узнал о символических ссылках Windows:

  2. Где я научился создавать пакетный скрипт Windows:

  3. Где я узнал, как удалить каталог в Windows или символическую ссылку на каталог в Windows: https://www.computerhope.com/mklink.htm#:~:text=To%20delete%20a%20symbolic%20link,link %20используйте%20команду%20del%20 .

    Добавлен акцент:

    Как удалить символическую ссылку?

    Чтобы удалить символическую ссылку, обращайтесь с ней как с любым другим каталогом или файлом. Если вы создали символическую ссылку с помощью команды, показанной выше, перейдите в корневой каталог, поскольку это «\Docs», и используйте команду [для символических ссылок на каталоги ]. Если вы создали символическую ссылку (<SYMLINK>) файла, чтобы удалить символическую ссылку, используйте команду [для символических ссылок на файлы ].

  4. Где я узнал, как получить путь к пакетному скрипту в Windows: Как получить путь к пакетному скрипту в Windows?

  5. Я только что узнал, что случайное использование каталога или символической ссылки на каталог попытается удалить все содержимое каталога, а не саму символическую ссылку (на каталог)! Осторожно! См.: Как удалить символическую ссылку в Windows?:

    Будь очень осторожен.

    Если у вас есть символическая ссылка, представляющая собой каталог (созданный с помощьюmklink /d), затем используяdelудалит все файлы в целевом каталоге (каталоге, на который указывает ссылка), а не только ссылку.

    РЕШЕНИЕ: rmdirс другой стороны, будет удалена только ссылка на каталог, а не то, на что она указывает.

git bash учитывает символические ссылки, созданные cygwin. Предупреждение заключается в том, что символическая ссылка не использует, например, «/cygdrive/c/directory», а вместо этого использует «/c/directory».

Вместо символических ссылок в окнах мне было проще написать небольшой bash-скрипт, который я поместил в свой каталог ~/bin. Чтобы запустить notepad++ с nppкоманда у меня есть этот файл:

$ cat ~/bin/npp

      #!/usr/bin/bash

'/c/Program Files (x86)/Notepad++/notepad++.exe' $@

И я получаю правильный синтаксис пути, перетаскивая файл из проводника в vim.

Команда окна mklink /J Link Targetкажется, больше не работает.

Другие вопросы по тегам