Wie kann ich Git dazu bringen, Symlinks zu folgen?


217

Wird mein Bestes ein Shell-Skript sein, das Symlinks durch Kopien ersetzt, oder gibt es eine andere Möglichkeit, Git anzuweisen, Symlinks zu folgen?

PS: Ich weiß, dass es nicht sehr sicher ist, aber ich möchte es nur in bestimmten Fällen tun.


5
Gibt es einen Nachteil bei der Verwendung von Hardlinks für so etwas?
Ehtesh Choudhury

12
Unter Windows 7 funktioniert "mklink / d" (symbolischer Verzeichnissink) nicht mit git, aber "mklink / j" (Juction) funktioniert einwandfrei.
Jojo

1
Wenn die Datei von einer Anwendung automatisch generiert wird, die sie so neu generiert, dass sie die Datei löscht und eine neue erstellt, ist dies ein Problem, das durch Hardlinks zu Dateien nicht gelöst werden kann.
Martin Pecka

1
@EhteshChoudhury Sie können keine festen Links für Verzeichnisse
erstellen

Antworten:


46

HINWEIS: Dieser Hinweis ist seit Git 1.6.1 gemäß Kommentar veraltet. Git hat sich früher so verhalten und tut es nicht mehr.


Git versucht standardmäßig, Symlinks zu speichern, anstatt ihnen zu folgen (aus Gründen der Kompaktheit und im Allgemeinen ist es das, was die Leute wollen).

Ich habe es jedoch versehentlich geschafft, Dateien über den Symlink hinaus hinzuzufügen, wenn der Symlink ein Verzeichnis ist.

Dh:

  /foo/
  /foo/baz
  /bar/foo --> /foo
  /bar/foo/baz

indem du es tust

 git add /bar/foo/baz

es schien zu funktionieren, als ich es versuchte. Dieses Verhalten war jedoch zu diesem Zeitpunkt von mir unerwünscht, sodass ich Ihnen darüber hinaus keine Informationen geben kann.


72
Die Commits 725b06050a083474e240a2436121e0a80bb9f175 und 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 führten Änderungen ein, die das Hinzufügen von Dateien über symlinked-Verzeichnisse hinaus verhinderten, sodass dies in Versionen von git seit 1.6.1
Mark Longair

1
$ git add src / main / path / ConvertSymlinkToDir fatal: 'src / main / path / ConvertSymlinkToDir' ist jenseits eines symbolischen Links
user1767316

2
@ user1767316 lies das Ganze und die Kommentare. Früher hat es funktioniert, heute nicht mehr. Software ändert sich, Stapelüberlauf akzeptiert jedoch keine Antworten. Ich habe klargestellt, dass dies nicht bereits funktioniert. Schau dir eine andere Antwort an.
Kent Fredric

yes @KentFrederic, aber das Verdrahten der genauen zurückgegebenen Fehlermeldung hilft dem Stack-Benutzer bei der Suche nach der Lösung für sein Problem. Es wurde versucht, die Abstimmung abzubrechen, aber leider gesperrt. Einerseits ist Ihre Antwort angesichts der Warnung richtig, andererseits sollte man der Antwort, die jetzt funktioniert, Vorrang
einräumen,

143

Was ich hinzugefügt habe, um die Dateien innerhalb eines Symlinks in Git zu bekommen (ich habe aber keinen Symlink verwendet):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Führen Sie diesen Befehl im von Git verwalteten Verzeichnis aus. TARGETDIRECTORYmuss erstellt werden, bevor das SOURCEDIRECTORYdarin montiert wird.

Es funktioniert gut unter Linux, aber nicht unter OS X! Dieser Trick hat mir auch bei Subversion geholfen. Ich verwende es, um Dateien aus einem Dropbox-Konto einzuschließen, in dem ein Webdesigner seine Aufgaben erledigt.


8
Wäre ein sehr schöner Ansatz, wenn Sudo nicht benötigt würde.
MestreLion

13
Verwenden Sie zum Rückgängigmachen dieser Bindung umount [mydir]. (+1 für Ihren tollen Tipp, @ user252400)
JellicleCat

10
Dies funktioniert nur während der Sitzung. Was ist der beste Weg, um es "ewig" zu machen?
Adobe

17
@Adobe: setzen Sie es in / etc / fstab, wie so: / sourcedir / targetdir keine binden
Alexander Garden

8
sshfs kann diese Art von Trick hier ausführen, ohne das sudo zu benötigen.
PypeBros

75

Warum nicht umgekehrt Symlinks erstellen? Das heißt, anstatt vom Git-Repository mit dem Anwendungsverzeichnis zu verknüpfen, verknüpfen Sie einfach umgekehrt.

Angenommen, ich richte eine installierte Anwendung ein, für ~/applicationdie eine Konfigurationsdatei erforderlich ist config.conf:

  • Ich füge config.confmeinem Git-Repository beispielsweise bei hinzu ~/repos/application/config.conf.
  • Dann erstelle ich einen Symlink aus, ~/applicationindem ich laufe ln -s ~/repos/application/config.conf.

Dieser Ansatz funktioniert möglicherweise nicht immer, hat aber bisher für mich gut funktioniert.


5
Scheint der einzige Weg zu sein, und es ist nicht so schlimm ... ich denke, dein Ansatz ist ziemlich elegant. Git verfolgt Inhalte, keine Dateien. Es macht also Sinn, alle Inhalte zusammenzuhalten und von dort aus mit anderen Orten zu
verknüpfen

12
In meinem Fall wollte ich einen Link von einem Git-Repo zu einem anderen, damit ich Dateien an beiden Orten bearbeiten und auf ihre jeweiligen Fernbedienungen zurückschicken kann. Unter Windows 7 hat eine Junction ("mklink / j") den Trick gemacht.
Jojo

3
natürlich. manchmal ist die Antwort einfach so einfach.
BBW vor Windows

Was ist, wenn Sie sowohl die Quelle als auch das Ziel angeben möchten? (weil beide zu verschiedenen Codes gehören, die Sie in verschiedenen Repositories haben möchten)
DrGC

1
Beantwortet die Frage nicht :( Ich wollte, dass ein Teil meines Repositorys mit meiner iCloud synchronisiert wird. Leider folgt iCloud keinen Symlinks, daher dachte ich, ich könnte git Symlinks folgen lassen und Originaldateien in iCloud speichern. Es stellt sich heraus, dass niemand folgt Symlinks: \
Jerry Green

49

Verwenden Sie stattdessen Hardlinks. Dies unterscheidet sich von einer weichen (symbolischen) Verbindung. Alle Programme, einschließlich git, behandeln die Datei als reguläre Datei. Beachten Sie, dass der Inhalt geändert werden kann, indem Sie entweder die Quelle oder das Ziel ändern .

Unter macOS (vor 10.13 High Sierra)

Wenn Sie Git und Xcode bereits installiert haben, installieren Sie den Hardlink . Es ist ein mikroskopisches Werkzeug, um harte Links zu erstellen .

Um die feste Verbindung herzustellen, einfach:

hln source destination

macOS High Sierra Update

Unterstützt Apple File System Verzeichnis-Hardlinks?

Verzeichnis-Hardlinks werden vom Apple File System nicht unterstützt. Alle Verzeichnis-Hardlinks werden in symbolische Links oder Aliase konvertiert, wenn Sie unter macOS von HFS + in APFS-Volume-Formate konvertieren.

Aus den APFS-FAQ auf developer.apple.com

Folgen Sie https://github.com/selkhateeb/hardlink/issues/31 für zukünftige Alternativen.

Unter Linux und anderen Unix-Varianten

Der lnBefehl kann feste Links herstellen:

ln source destination

Unter Windows (Vista, 7, 8,…)

Jemand hat vorgeschlagen, mit mklink eine Junction unter Windows zu erstellen, aber ich habe es nicht versucht:

mklink /j "source" "destination"

7
Nur eine Anmerkung: Dies ist im Grunde das, wonach ich gesucht habe, aber dann habe ich erfahren, dass ein Hardlink unter Linux leider keine Dateisystemgrenzen überschreiten kann (was mein Anwendungsfall ist).
Sdaau

26
Sie können nicht fest mit Verzeichnissen verknüpfen, oder?
Nanne

1
ln source destinationfunktioniert auch unter OS X. Getestet auf El Capitan.
Mahdi Dibaiee

7
@Nanne nein, aber du kannst : cp -al source destination. `-l 'bedeutet Hardlink-Dateien anstatt zu kopieren.
Paolo

6
Leider können Sie keine Verzeichnisse oder über Dateisystemgrenzen hinweg fest verknüpfen. Dies macht diese Lösung für mich zweifach nicht praktikabel.
Konrad Rudolph

25

Dies ist ein Pre-Commit-Hook, der die Symlink-Blobs im Index durch den Inhalt dieser Symlinks ersetzt.

Geben Sie dies ein .git/hooks/pre-commitund machen Sie es ausführbar:

#!/bin/sh
# (replace "find ." with "find ./<path>" below, to work with only specific paths)

# (these lines are really all one line, on multiple lines for clarity)
# ...find symlinks which do not dereference to directories...
find . -type l -exec test '!' -d {} ';' -print -exec sh -c \
# ...remove the symlink blob, and add the content diff, to the index/cache
    'git rm --cached "$1"; diff -au /dev/null "$1" | git apply --cached -p1 -' \
# ...and call out to "sh".
    "process_links_to_nondir" {} ';'

# the end

Anmerkungen

Wir verwenden so oft wie möglich POSIX-kompatible Funktionen. ist jedoch diff -amöglicherweise unter anderem nicht POSIX-konform.

Es kann einige Fehler in diesem Code geben, obwohl er etwas getestet wurde.


4
Es ist großartig zu sehen, wie versucht wird, die Frage für Dateien und nicht für Verzeichnisse zu beantworten. Beachten Sie jedoch, dass die oben zeigt noch typechangein git statusfür die Dateien , die tatsächlich Symlinks sind allerdings git jetzt Dinge , die sie nicht sind.
David Fraser

1
Danke dafür; wollte nur wissen, was ist process_links_to_nondir?
Sdaau

@sdaau Dies ist der Name /, argv[0]der als Befehlsname für den shProzess verwendet wird. (Ich brauchte ein bisschen, um das herauszufinden, da ich mich auch nicht daran erinnerte, was es war ☺😃)
Abbafei

3
@Abbafei Können Sie das Skript so ändern, dass es unter Ubuntu (14.04) funktioniert? Es zeigt find: missing argument to -exec'. Möglicherweise ist eine schrittweise Befehlsausführung erforderlich, anstatt alles in einer einzigen Zeile zu kombinieren.
Khurshid Alam

1
@ KhurshidAlam Bei mir hat es funktioniert, die kommentierten Zeilen zwischen den Befehlszeilen zu entfernen. Der Hook funktioniert jedoch nicht wie erwartet (ich bekomme das typechangewie @DavidFraser, aber die verknüpfte Datei scheint nicht mehr inszeniert zu sein)
Scz

14

Ein MacOS(ich habe Mojave / 10.14, gitVersion 2.7.1) verwenden bindfs.

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

Es wurde durch andere Kommentare angedeutet, aber in anderen Antworten nicht eindeutig angegeben. Hoffentlich spart dies jemandem etwas Zeit.


scheint großartig für Teams zu sein, die alle auf Mac OS laufen. Ich denke, die unten beschriebenen harten Links sollten für Windows und Linux funktionieren.
Devin G Rhode

Dies war hilfreich, und ich denke, die beste Lösung für eine nützliche, aber fehlende Funktion in MacOS. Beachten Sie jedoch, dass ich Failed to resolve... No such file or directoryFehler erhalten habe, es sei denn, ich habe mit dem Befehl vollständige Pfadnamen verwendetbindfs .
Electromaggot

Danke @electromaggot. Klarstellung hinzugefügt, dass vollständige Pfade notwendig sind
ijoseph

1
Funktioniert hervorragend auf Macos Catalina!
Jerry Green

13

Ich habe schon seit einiger Zeit Dateien jenseits von Symlinks hinzugefügt. Dies funktionierte früher einwandfrei, ohne besondere Vorkehrungen zu treffen. Seit ich auf Git 1.6.1 aktualisiert habe, funktioniert dies nicht mehr.

Möglicherweise können Sie zu Git 1.6.0 wechseln, damit dies funktioniert. Ich hoffe, dass eine zukünftige Version von Git eine Flagge hat, git-adddamit es wieder Symlinks folgen kann.


12

Ich habe es satt, dass jede Lösung hier entweder veraltet ist oder root benötigt, also habe ich eine LD_PRELOAD-basierte Lösung erstellt (nur Linux).

Es fügt sich in Gits Interna ein und überschreibt das "Ist das ein Symlink?" Funktion, mit der Symlinks als Inhalt behandelt werden können. Standardmäßig sind alle Links außerhalb des Repos inline. Siehe den Link für Details.


Sehr kreative Lösung LD_PRELOADzum Überschreiben von Bibliotheksfunktionen!
iBug

Ja, aber es sollte hier näher ausgeführt werden. Können Sie das tun?
Peter Mortensen

Ich bin mir nicht sicher, wie viel Ausarbeitung helfen würde. Wenn ich nicht den gesamten Quellcode kopiere, stützt sich diese Antwort immer auf diesen Link, über den auch eine Readme-Datei gefunden werden kann. Aber ja, ich denke, ich könnte die wichtigen Teile der Readme-Datei reproduzieren.
Alcaro

Dies wird unter OS X (Mojave 10.14.2) nicht kompiliert. Erhalten Sie vier Fehler, die sich über 'strchrnul' beschweren (meinten Sie 'strchr'?) Und einen über '__xstat64' (meinten Sie '__lxstat64'?). Schließlich erhalte ich den Fehler "Mitgliederzugriff auf unvollständigen Typ 'dirent64'". Passiert unabhängig davon, ob ich "make", "make OPT = 1" oder "sh install.sh" verwende.
Erik Veland

@ErikVeland Ich habe es ein bisschen versucht, aber es scheint, dass OSX weder LD_PRELOAD noch ähnliches unterstützt. Verschiedene Dokumente schlagen verschiedene Dinge vor, aber sie sind alle mehrere Jahre alt, und Apple liebt es, Dinge abzulehnen. Ich konnte keinen von ihnen zum Laufen bringen. Es tut uns leid.
Alcaro

6

Mit Git 2.3.2+ (Q1 2015), gibt es einen anderen Fall , in dem Git wird nicht Symlink folgen mehr: siehe begehen e0d201b von Junio C Hamano ( gitster) (Haupt - Git - Maintainer)

apply: Berühren Sie keine Datei über einen symbolischen Link hinaus

Da Git symbolische Links als symbolische Links verfolgt, kann ein Pfad, dessen Hauptteil einen symbolischen Link enthält (z. B. path/to/dir/filewo path/to/dirsich ein symbolischer Link zu einem anderen Ort befindet, sei es innerhalb oder außerhalb des Arbeitsbaums), niemals in einem gültigen Patch erscheinen , es sei denn, derselbe Patch entfernt zuerst den symbolischen Link, damit dort ein Verzeichnis erstellt werden kann.

Erkennen Sie einen solchen Patch und lehnen Sie ihn ab.

Wenn eine Eingabe eine symbolische Verknüpfung erstellt path/to/dirund dann eine Datei erstellt path/to/dir/file, müssen wir sie als Fehler kennzeichnen, ohne tatsächlich eine path/to/dirsymbolische Verknüpfung im Dateisystem zu erstellen .

Stattdessen überprüfen wir für jeden Patch in der Eingabe, der einen Pfad (dh ein Nichtlöschen) im Ergebnis hinterlässt, alle führenden Pfade anhand des resultierenden Baums, den der Patch erstellen würde, indem wir alle Patches in der Eingabe und dann das Ziel des Patches untersuchen Anwendung (entweder der Index oder der Arbeitsbaum).

Auf diese Weise können wir:

  • einen Unfug oder einen Fehler abfangen, um gleichzeitig einen symbolischen Link path/to/dirund eine Datei hinzuzufügen path/to/dir/file,
  • Dabei wird ein gültiger Patch zugelassen, der ein Symbol entfernt link path/to/dirund dann eine Datei hinzufügt path/to/dir/file.

Das heißt, in diesem Fall ist die Fehlermeldung keine generische "%s: patch does not apply", sondern eine spezifischere:

affected file '%s' is beyond a symbolic link

4

Hmmm, mount --bindscheint bei Darwin nicht zu funktionieren.

Hat jemand einen Trick, der das tut?

[bearbeitet]

OK, ich fand die Antwort unter Mac OS X, einen Hardlink zu erstellen. Abgesehen davon, dass diese API nicht über verfügbar gemacht wird ln, müssen Sie dazu Ihr eigenes kleines Programm verwenden. Hier ist ein Link zu diesem Programm:

Erstellen von Verzeichnis-Hardlinks in Mac OS X.

Genießen!


1
Wenn das Zielverzeichnis dieses Hardlinks ein Unterverzeichnis eines anderen Git-Repos ist, wäre dies ein Chaos. Das Ausführen von Git-Operationen im Hardlink würde für dieses andere Git-Repo gelten. Überprüfen Sie einfach, was Sie tun.
Yegle

4
Dies ist über code.google.com/p/bindfs möglich, das über den Port installiert werden kann.
Kit Sunde

0

Ich verwende Git 1.5.4.3 und es folgt dem übergebenen Symlink, wenn es einen abschließenden Schrägstrich hat. Z.B

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/

5
Zumindest unter OSX führt dies zufatal: 'src/' is beyond a symbolic link
Dan Rosenstark

2
Wie von @Mark Longair erklärt, funktionierte dies nur bis Git 1.6.1
MestreLion

das war mein Problem, danke!
Mike Q

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.