Git Bash Shell kann keine symbolischen Links erstellen

74

Wenn ich versuche, einen symbolischen Link aus der Git Bash-Shell zu erstellen, schlägt dies jedes Mal fehl:

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

Abgesehen von der Fehlermeldung wird lediglich ein leeres Verzeichnis mit dem Namen (in diesem Fall) erstellt testlink.

Ich sehe kein Problem mit der lnausführbaren Datei. Zum Beispiel gehört es mir und ist als ausführbar gekennzeichnet:

$ which ln
/bin/ln

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

Ich besitze auch das aktuelle Verzeichnis ( ~das ist /c/Users/bzisad0):

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

Ich habe Administratorrechte und habe versucht, die Git Bash-Shell mit "Als Administrator ausführen" zu öffnen, aber das macht keinen Unterschied.

Ich habe versucht, die Windows-Eigenschaften für zu öffnen ln.exeund die Berechtigungsstufe auf "Dieses Programm als Administrator ausführen" festzulegen, aber das hilft nicht.

Ich habe in Windows die Eigenschaften Sicherheit -> Erweitert aufgerufen und mich (und nicht die Gruppe Administratoren) zum Eigentümer gemacht, aber das behebt auch nichts.

Ich bin ratlos. Ich weiß nicht, ob diese Fehlermeldung letztendlich von ln, von Bash oder von Windows stammt oder wie mir möglicherweise die Berechtigung fehlt. Wie kann ich dem auf den Grund gehen?

Bilderstürmer
quelle

Antworten:

71

Es ist möglich, wenn auch äußerst umständlich, einen Symlink in MSYSGIT zu erstellen.

Zuerst müssen wir sicherstellen, dass wir unter Windows sind. Hier ist eine Beispielfunktion, um dies zu überprüfen:

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

Das können wir jetzt nicht cmd /C, weil MSYSGIT mit diesem Argument forniziert und es in verwandelt C:. Versuchen /KSie auch nicht, es zu verwenden , es funktioniert nur, wenn Sie kein K:Laufwerk haben.

Während dieser Wert bei Programmargumenten ersetzt wird, wird er bei Heredocs nicht verwendet. Wir können dies zu unserem Vorteil nutzen:

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

Außerdem: Beachten Sie, dass ich aufgenommen habe, /Dweil ich nur an Verzeichnissymlinks interessiert bin. Windows hat diese Unterscheidung. Mit viel Aufwand könnten Sie eine ln() { ... }Funktion schreiben , die die Windows-API umschließt und als vollständige Drop-In-Lösung dient, aber das ist ... eine Übung für den Leser.


Bearbeiten: Als Dankeschön für die akzeptierte Antwort finden Sie hier eine umfassendere Funktion.

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

Beachten Sie auch einige Dinge:

  1. Ich habe das gerade geschrieben und es kurz unter Win7 und Ubuntu getestet. Probieren Sie es zuerst aus, wenn Sie ab 2015 Windows 9 verwenden.
  2. NTFS verfügt über Analysepunkte und Verbindungspunkte. Ich habe Analysepunkte gewählt, weil es eher ein tatsächlicher Symlink ist und für Dateien oder Verzeichnisse funktioniert, aber Verbindungspunkte hätten den Vorteil, eine verwendbare Lösung in XP zu sein, außer es ist nur für Verzeichnisse.
  3. Einige Dateisysteme, insbesondere die FAT-Systeme, unterstützen keine Symlinks. Moderne Windows-Versionen unterstützen das Booten von ihnen nicht mehr, aber Windows und Linux können sie mounten.

Bonusfunktion: Link entfernen.

# 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
}
Camilo Martin
quelle
3
Die Parameter für lnsind nicht wirklich rückwärts, da sie mehrere Parameter unterstützen. Sie können einfach eine Reihe von Dateien und ein Verzeichnis als Ziel auflisten und es wird funktionieren :) Außerdem ist es in der normalen Reihenfolge ähnlich cpund mvweniger verwirrend.
Wolph
2
@Wolph See, es ist großartig, dass ich nicht versucht habe, eine "Drop-In" -Lösung zu erstellen, lol. Ich hatte keine Ahnung, dass Sie mehr als zwei Wege gehen könnten ln.
Camilo Martin
2
Hey Mann, das ist eine wirklich süße Antwort, und das fühlt sich an wie ein Trottel, aber ... WARUM mussten Sie die Parameterreihenfolge umkehren? Es ist "Link Ziel Linkname" nicht umgekehrt. Pls. (Bearbeiten: OK Ich weiß, es liegt daran, dass Sie möchten, dass die Ein-Parameter-Überladung den Linknamen überprüft, ob es sich um einen Link handelt oder nicht, während Unix lndies nicht tut. Der Punkt bleibt jedoch bestehen.)
Steven Lu
2
Ich komme aus der Zukunft, habe aber vergessen, unterwegs Windows 9 zu kaufen.
Greg
6
Ich bin im Jahr 2019 noch kein Windows 9 :)
Maxim Mazurok
40

Für mein Setup führt Git für Windows 2.11.0, das unter Windows 8.1 installiert export MSYS=winsymlinks:nativestrictist, den hier beschriebenen Trick aus: https://github.com/git-for-windows/git/pull/156 Es ist wichtig, die Git Bash-Shell zu starten Als Administrator wie unter Windows konnten nur Administratoren die symbolischen Links erstellen. Also, um tar -xfArbeit zu machen und die erforderlichen Symlinks zu erstellen:

  1. Führen Sie die Git Bash-Shell als Administrator aus
  2. Lauf export MSYS=winsymlinks:nativestrict
  3. Führen Sie tar aus
Mikhail Filimonov
quelle
1
Es ist die wahre Antwort ~
Fatfatson
3
Sie müssen nicht als Administrator ausgeführt werden, wenn Sie den Windows-Entwicklermodus aktivieren
Sebastian
ln -s currentFile newLinkfunktioniert auch mit diesem Ansatz (nicht nur Teer). Der erstellte Link wird im Windows-Explorer als Verknüpfung angezeigt. Wenn Sie der Verknüpfung folgen, wird jedoch nicht zum Pfad des anderen Ordners gesprungen, sondern Sie sehen einen Pfad wie C:\currentFolder\newLink. Ich habe noch nie einen solchen Windows-Link gesehen!
Josiah Yoder
Ich habe hier ein Beispiel mit Beispielen und Bildern entwickelt: stackoverflow.com/a/63325536/1315009 - Auch von dort nach hier verlinkt.
Xavi Montero
23

Eine Problemumgehung besteht darin, mklinkvon Bash aus zu starten . Auf diese Weise können Sie auch entweder einen Symlink oder eine Junction erstellen .

Achten Sie darauf, den mklinkBefehl als einzelnes Argument an cmd...

cmd  /c "mklink link target"

Hier sind die Optionen für 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.

Wenn Sie stattdessen Links über eine GUI erstellen möchten ... Ich empfehle die Link Shell Extension , ein Windows Explorer-Plugin zum Erstellen symbolischer Links, Hardlinks, Junctions und Volume Mountpoints. Ich benutze es seit Jahren!

Symlinks können lebensrettend sein, wenn Sie ein kleineres SSD-Laufwerk auf Ihrem System C: -Laufwerk haben und einige aufgeblähte Ordner, die nicht auf SSD sein müssen, mit anderen Laufwerken verknüpfen müssen. Ich benutze den kostenlosen WinDirStat , um die Speicherplatzfresser zu finden.

Tony O'Hagan
quelle
2
MSYSGIT schafft es durchdringend genug, den Benutzer weiter zu sodomisieren, indem es die Ausführung unmöglich macht, cmd /cda /ces immer ersetzt wird C:(das Dateisystem verwendet /c/Windows/...Konventionen). Zum Glück können Sie tun, echo -n | cmd /k ...wenn Sie kein K:Laufwerk haben. Brillant.
Camilo Martin
1
Gibt es einen anderen Grund, warum Leute sagen "Windows hat eine schlechte Unterstützung für Symlinks", außer der Tatsache, dass aus Sicherheitsgründen ein Administrator erforderlich ist? Sie können einem Benutzer das Recht einräumen, mit secpol.msc nicht erhöhte Symlinks zu erstellen.
Justin Dunlap
1
@JustinDunlap Die frühe Implementierung für die Verknüpfung in Windows NT / 2000 war schlecht und sah nachträglich nur wie ein "Hack" aus (Vista / Win7 / 8-Implementierungen bereinigten dies). Die meisten Windows-Entwickler / -Sysadmins sind nicht daran gewöhnt, sie zu verwenden, und die MS-Dokumentation bezieht sich fast nie auf sie. Folglich berücksichtigen viele Windows-Entwickler sie nicht in Softwarelösungen! Ich vermute, dass viele Link-bezogene Sicherheitsszenarien von Produktanbietern nicht berücksichtigt wurden, daher hat MS sie "nur für Administratoren" erstellt. Unter Linux / OSX / Unix sind sie Mainstream / ermutigt, sodass die meisten Apps mit ihnen gut getestet sind und voraussichtlich mit ihnen funktionieren.
Tony O'Hagan
6
@CamiloMartin /ckann auf diese //cWeise maskiert werden, um den Powershell-Befehl anstelle des Laufwerks C: zu erhalten. Ich wollte auch ein paar Beispiele hinzufügen, wie genau die Syntax aussehen muss, um sie mklinkin der Git-Bash-Shell zu verwenden, da ich eine Weile gebraucht habe, um sie herauszufinden. Wie Tony beschreibt, mklinkfunktioniert das Zitieren des gesamten m- Befehls wie folgt: cmd //c "mklink .\b_dir\test.txt .\a_dir\test.txt"Oder Sie können die Anführungszeichen weglassen und den Backslahes folgendermaßen entkommen:cmd //c mklink .\\b_dir\\test.txt .\\a_dir\\test.txt
Grant Humphries
1
@GrantHumphries Großartig, wusste nichts davon //c. Übrigens sind in solchen Fällen einfache Anführungszeichen normalerweise bequemer, da in diesen Zeichenfolgen keine Analyse durchgeführt wird.
Camilo Martin
15

Ich glaube, dass das lnmit msysGit gelieferte einfach versucht, seine Argumente zu kopieren, anstatt mit Links zu fummeln. Dies liegt daran, dass Links nur auf NTFS-Dateisystemen funktionieren und das MSYS-Team ln nicht erneut implementieren wollte.

Siehe zum Beispiel http://mingw.5.n7.nabble.com/symbolic-link-to-My-Documents-in-MSYS-td28492.html

Austin Hastings
quelle
2
Du hast Recht. Als ich es gerade versuchte, ln file1 file2; ln file1 file3; ln file1 file4bekam ich eine scheinbar gültige Linkanzahl in der Ausgabe von ls -l. Beachten Sie jedoch, dass dies fehlschlägt, ln: hard link not allowed for directory.wenn Sie dies versuchen.
Austin Hastings
1
Haben die meisten modernen Windows-Systeme nicht bereits NTFS? Haben sie sie auch nicht seit Windows NT 3.1 im Jahr 1993 (laut vertrauenswürdiger alter Wikipedia)?
Tryse
2
Ja, es scheint eine krasse Auslassung zu sein, und keine, die sie Microsoft vorwerfen können.
Bilderstürmer
1
@AustinHastings, Linux erlaubt auch keine festen Links in Verzeichnissen, so dass dieser Teil immer noch mit übereinstimmt ln.
Trysis
1
@AustinHastings Nein, FAT wird nicht wirklich unterstützt. Sie können derzeit unterstützte Versionen von Windows nicht mehr unter FAT installieren.
Camilo Martin
2

Da dies einer der Top-Links ist, die bei der Suche nach Symlinks in Msys oder Git Bash angezeigt werden, war die Antwort, set MSYS=winsymlinks:nativebeim Aufrufen git-cmd.exe(ich führe ConEmu aus) hinzuzufügen oder dieselbe Zeile in der zu kommentierenmsys2_shell.bat

Swee Lim
quelle
1
Ich habe es versucht und msys kopiert immer noch und erstellt keinen tatsächlichen Link - ich bin auf Win10
0fnt
@sweelim Bitte klären Sie, welche git-cmd.exeSie verwenden, wenn dies für Sie funktioniert.
Clacke
Ich habe gerade versucht MSYS2=winsymlinks:native, MSYS=winsymlinks:nativeund CYGWIN=winsymlinks:native, und die offizielle Git Windows-Distributionsversion verwendet 2.8.3.windows.1. ln -skein Symlink, es wird rekursiv kopiert.
Clacke
2

Erweitern Sie die Antwort von Camilo Martin, wenn Sie den Parameterschalter / j für Windows 10 verwenden müssen. Andernfalls wird der Anruf nur zurückgegeben. "Sie haben nicht genügend Berechtigungen, um diesen Vorgang auszuführen."

Dies funktioniert für git bash 2.20.1.windows.1 / MINGW64 (Windows 10) ohne Administratorrechte (wenn Sie sowohl / old / path als auch / link / path lesen / schreiben können:

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
Oliver Zendel
quelle
1

Ich bevorzuge Powershell gegenüber CMD und dachte, ich würde die Powershell-Version davon teilen.

In meinem Fall besteht es darin, Symlinks zu erstellen, die die Datei ~ /.$ mit der Datei ~ / dotfiles / $ für Dotfile-Konfigurationen verknüpfen. Ich habe dies in ein .shSkript eingefügt und es mit git-bash ausgeführt:

powershell New-Item -ItemType SymbolicLink\
    -Path \$Home/.$file\
    -Target \$Home/dotfiles/$file
Christian Fosli
quelle
0

Für alle, die daran interessiert sind, wie dies in Windows 10 Git Bash 2.28.0.0.1 erreicht werden kann, müssen Sie dem ln -sBefehl das Präfix " MSYS=..statt export MSYS=..zuerst ausführen" voranstellen , nämlich nur einen Befehl:

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