Comment faire pour que Git suive les liens symboliques?

217

Est-ce que mon mieux sera un script shell qui remplace les liens symboliques par des copies, ou existe-t-il une autre façon de dire à Git de suivre les liens symboliques?

PS: Je sais que ce n'est pas très sécurisé, mais je ne veux le faire que dans quelques cas spécifiques.

Mat
la source
5
y a-t-il un inconvénient à utiliser des liens durs pour quelque chose comme ça?
Ehtesh Choudhury
12
Avec Windows 7, "mklink / d" (lien symbolique de répertoire) ne fonctionne pas avec git, mais "mklink / j" (juction) fonctionne très bien.
yoyo
1
Si le fichier est généré automatiquement par une application qui le régénère de telle manière qu'il supprime le fichier et en crée un nouveau, alors oui, c'est un problème que les liens durs vers les fichiers ne résoudront pas.
Martin Pecka
1
@EhteshChoudhury vous ne pouvez pas créer de liens durs pour les répertoires
Gaurav Kansal

Réponses:

46

REMARQUE: cet avis est désormais obsolète selon le commentaire depuis Git 1.6.1. Git se comportait de cette façon et ne le fait plus.


Git essaie par défaut de stocker les liens symboliques au lieu de les suivre (par souci de compacité, et c'est généralement ce que les gens veulent).

Cependant, j'ai accidentellement réussi à le faire ajouter des fichiers au-delà du lien symbolique lorsque le lien symbolique est un répertoire.

C'est à dire:

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

en faisant

 git add /bar/foo/baz

cela a semblé fonctionner quand je l'ai essayé. Ce comportement n'était cependant pas souhaité par moi à l'époque, donc je ne peux pas vous donner d'informations au-delà de cela.

Kent Fredric
la source
72
Les validations 725b06050a083474e240a2436121e0a80bb9f175 et 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 ont introduit des changements qui vous ont empêché d'ajouter des fichiers au-delà des répertoires liés par des liens symboliques, donc cela ne fonctionnera pas dans les versions de git depuis le 1.6.1
Mark Longair
1
$ git add src / main / path / ConvertSymlinkToDir fatal: 'src / main / path / ConvertSymlinkToDir' est au-delà d'un lien symbolique
user1767316
2
@ user1767316 lire le tout et les commentaires. Il fonctionnait, il ne fonctionne plus. Le logiciel change, mais les réponses acceptées par dépassement de pile ne le font pas. J'ai précisé que cela ne fonctionne pas déjà. Regardez une autre réponse.
Kent Fredric
oui @KentFrederic mais en câblant le message d'erreur exact, la recherche de la solution à son problème a été aidée par l'utilisateur de pile. a essayé d'annuler le vote négatif mais verrouillé désolé. D'une part, votre réponse est juste compte tenu de l'avertissement, d'autre part, vous devez donner la priorité à une réponse qui fonctionne maintenant plutôt que par le passé
user1767316
144

Ce que j'ai fait pour ajouter les fichiers d'un lien symbolique dans Git (je n'ai pas utilisé de lien symbolique mais):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Exécutez cette commande dans le répertoire géré par Git. TARGETDIRECTORYdoit être créé avant d' SOURCEDIRECTORYy être monté.

Cela fonctionne bien sous Linux, mais pas sous OS X! Cette astuce m'a également aidé avec Subversion. Je l'utilise pour inclure des fichiers à partir d'un compte Dropbox, où un webdesigner fait son travail.

user252400
la source
8
Ce serait une très bonne approche si sudo n'était pas nécessaire.
MestreLion
13
Pour annuler cette liaison, utilisez umount [mydir]. (+1 pour votre excellent conseil, @ user252400)
JellicleCat
10
Cela ne fonctionne que pendant la session. Quelle est la meilleure façon de la rendre "éternelle"?
Adobe
17
@Adobe: mettez-le dans / etc / fstab, comme ceci: / sourcedir / targetdir aucune liaison
Alexander Garden
8
sshfs peut réaliser ce genre de truc sans avoir besoin du sudo, ici.
PypeBros
75

Pourquoi ne pas créer des liens symboliques dans l'autre sens? Au lieu de lier le référentiel Git au répertoire d'application, il suffit de lier l'inverse.

Par exemple, disons que je configure une application installée dans ~/applicationqui a besoin d'un fichier de configuration config.conf:

  • J'ajoute config.confà mon référentiel Git, par exemple, à ~/repos/application/config.conf.
  • Ensuite, je crée un lien symbolique à partir de ~/applicationen cours d'exécution ln -s ~/repos/application/config.conf.

Cette approche peut ne pas toujours fonctionner, mais elle a bien fonctionné jusqu'à présent.

spire
la source
5
Semble être le seul moyen, et ce n'est pas si mal ... je pense que le vôtre est une approche assez élégante. git suit le contenu, pas les fichiers. Donc, garder tout le contenu ensemble et créer des liens symétriques à partir de là vers d'autres endroits a du sens
MestreLion
12
Dans mon cas, je voulais un lien d'un dépôt git à un autre, afin que je puisse modifier les fichiers dans l'un ou l'autre emplacement et les remettre sur leurs télécommandes respectives. Sous Windows 7, une jonction ("mklink / j") a fait l'affaire.
yoyo
3
bien sûr. Parfois, la réponse est aussi simple que cela.
BBW avant Windows
que faire si vous voulez git à la fois la source ET la destination? (parce que les deux appartiennent à des codes différents que vous souhaitez avoir dans différents référentiels)
DrGC
1
Ne répond pas à la question :( Je voulais qu'une partie de mon référentiel soit synchronisée avec mon iCloud. Malheureusement, iCloud ne suit pas les liens symboliques, donc j'ai pensé que je pourrais faire git suivre les liens symboliques et stocker les fichiers originaux dans iCloud. Il s'avère que personne ne suit liens symboliques: \
Jerry Green
49

Utilisez plutôt des liens physiques. Cela diffère d'un lien souple (symbolique). Tous les programmes, y compris git, traiteront le fichier comme un fichier normal. Notez que le contenu peut être modifié en modifiant soit la source ou la destination.

Sur macOS (avant 10.13 High Sierra)

Si vous avez déjà installé git et Xcode, installez hardlink . C'est un outil microscopique pour créer des liens durs .

Pour créer le lien dur, simplement:

hln source destination

mise à jour macOS High Sierra

Le système de fichiers Apple prend-il en charge les liens matériels des répertoires?

Les liens matériels d'annuaire ne sont pas pris en charge par Apple File System. Tous les liens matériels de répertoire sont convertis en liens symboliques ou alias lorsque vous convertissez des formats de volume HFS + en APFS sur macOS.

De la FAQ APFS sur developer.apple.com

Suivez https://github.com/selkhateeb/hardlink/issues/31 pour de futures alternatives.

Sous Linux et autres versions Unix

La lncommande peut créer des liens durs:

ln source destination

Sous Windows (Vista, 7, 8,…)

Quelqu'un a suggéré d'utiliser mklink pour créer une jonction sous Windows, mais je ne l'ai pas essayé:

mklink /j "source" "destination"
fregante
la source
7
Juste une note: c'est essentiellement ce que je cherchais, mais j'ai ensuite appris que sous Linux, un lien physique ne peut malheureusement pas franchir les limites du système de fichiers (ce qui est mon cas d'utilisation).
sdaau
26
Vous ne pouvez pas créer de liens physiques vers des répertoires, n'est-ce pas?
Nanne
1
ln source destinationfonctionne également sous OS X. Testé sur El Capitan.
Mahdi Dibaiee
7
@Nanne non, mais vous pouvez faire: cp -al source destination. `-l 'signifie des fichiers de lien dur au lieu de copier.
Paolo
6
Malheureusement, vous ne pouvez pas créer de lien physique entre les répertoires ou au-delà des limites du système de fichiers. Cela rend cette solution double irréalisable pour moi.
Konrad Rudolph
25

Il s'agit d'un hook de pré-validation qui remplace les objets blob de liens symboliques dans l'index, par le contenu de ces liens symboliques.

Mettez cela .git/hooks/pre-commit, et rendez-le exécutable:

#!/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

Remarques

Nous utilisons autant que possible des fonctionnalités conformes à POSIX; cependant, diff -an'est pas compatible POSIX, peut-être entre autres.

Il peut y avoir des erreurs / erreurs dans ce code, même s'il a été quelque peu testé.

Abbafei
la source
4
C'est formidable de voir une tentative de répondre à la question des fichiers et non des répertoires. Cependant, notez que le montrera encore plus haut typechangedans git statusles fichiers qui sont en fait des liens symboliques si les choses qu'ils sont maintenant git pas.
David Fraser
1
Merci pour cela; je voulais juste savoir, c'est quoi process_links_to_nondir?
sdaau
@sdaau C'est le nom / argv[0]qui est utilisé comme nom de commande pour le shprocessus. (Cela m'a pris un peu de temps pour comprendre cela, car je ne me souvenais pas non plus de ce que c'était ☺😃)
Abbafei
3
@Abbafei Pouvez-vous modifier le script pour le faire fonctionner sur Ubuntu (14.04)? Ça se voit find: missing argument to -exec'. Peut-être qu'une exécution de commande étape par étape est nécessaire au lieu de canaliser et de tout combiner en une seule ligne.
Khurshid Alam
1
@KhurshidAlam Pour moi, cela a fonctionné de supprimer les lignes commentées entre les lignes de commande. Cependant, le crochet ne fonctionne pas comme prévu (j'obtiens le typechangemême @DavidFraser, mais le fichier lié ne semble plus être mis en scène)
Scz
14

Sur MacOS(j'ai Mojave / 10.14, gitversion 2.7.1), utilisez 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>

Il a été laissé entendre par d'autres commentaires, mais n'est pas clairement fourni dans d'autres réponses. Espérons que cela fera gagner du temps à quelqu'un.

ijoseph
la source
semble génial pour les équipes qui fonctionnent toutes sur mac os, je pense que les liens durs décrits ci-dessous devraient fonctionner pour Windows et Linux.
Devin G Rhode
Cela a été utile et je pense que la meilleure solution pour une capacité utile mais manquante dans MacOS. Notez cependant que j'obtenais Failed to resolve... des No such file or directoryerreurs à moins que j'utilise des noms de chemin complets avec la bindfscommande.
electromaggot
Merci @electromaggot. Ajout de la clarification que les chemins complets sont nécessaires
ijoseph
1
Fonctionne très bien sur macos Catalina!
Jerry Green
13

J'avais l'habitude d'ajouter des fichiers au-delà des liens symboliques depuis un certain temps maintenant. Cela fonctionnait très bien, sans prendre de dispositions spéciales. Depuis que j'ai mis à jour vers Git 1.6.1, cela ne fonctionne plus.

Vous pourrez peut-être passer à Git 1.6.0 pour que cela fonctionne. J'espère qu'une future version de Git aura un indicateur lui git-addpermettant de suivre à nouveau les liens symboliques.

Erik Schnetter
la source
12

Je me suis fatigué que chaque solution ici soit obsolète ou nécessitant un root, j'ai donc créé une solution basée sur LD_PRELOAD (Linux uniquement).

Il se connecte aux internes de Git, remplaçant le "est-ce un lien symbolique?" , permettant aux liens symboliques d'être traités comme leur contenu. Par défaut, tous les liens vers l'extérieur du référentiel sont en ligne; voir le lien pour plus de détails.

Alcaro
la source
Solution très créative utilisant LD_PRELOADpour remplacer les fonctions de la bibliothèque!
iBug
Oui, mais cela devrait être développé ici. Peux-tu faire ça?
Peter Mortensen
Je ne sais pas dans quelle mesure l'élaboration serait utile; sauf si je copypaste le code source entier, cette réponse reposera toujours sur ce lien, où un fichier Lisez-moi peut également être trouvé. Mais oui, je suppose que je pourrais reproduire les parties importantes du fichier Lisez-moi.
Alcaro
Cela ne se compile pas sur OS X (Mojave 10.14.2). Obtenez quatre erreurs se plaignant de «strchrnul» (vouliez-vous dire «strchr»?) Et une de «__xstat64» (vouliez-vous dire «__lxstat64»?). Enfin, j'obtiens une erreur "Accès membre en type incomplet 'dirent64'". Cela arrive peu importe si j'utilise "make", "make OPT = 1" ou "sh install.sh".
Erik Veland
@ErikVeland J'ai essayé un peu, mais il semble qu'OSX ne supporte pas LD_PRELOAD, ni rien de similaire. Divers documents suggèrent différentes choses, mais ils ont tous plusieurs années, et Apple aime déprécier les trucs; Je n'ai pas réussi à faire fonctionner l'un d'eux. Désolé.
Alcaro
6

Avec Git 2.3.2+ (T1 2015), il y a un autre cas où Git ne suivra plus le lien symbolique: voir commit e0d201b par Junio ​​C Hamano ( gitster) (mainteneur principal de Git)

apply: ne touchez pas un fichier au-delà d'un lien symbolique

Étant donné que Git suit les liens symboliques en tant que liens symboliques, un chemin qui a un lien symbolique dans sa partie principale (par exemple path/to/dir/file, oùpath/to/dir trouve un lien symbolique vers un autre endroit, que ce soit à l'intérieur ou à l'extérieur de l'arborescence de travail) ne peut jamais apparaître dans un patch qui s'applique valablement. , sauf si le même patch supprime d'abord le lien symbolique pour permettre la création d'un répertoire à cet endroit.

Détectez et rejetez un tel patch.

De même, lorsqu'une entrée crée un lien symbolique path/to/dirpuis crée un fichier path/to/dir/file, nous devons le signaler comme une erreur sans réellement créer de path/to/dirlien symbolique dans le système de fichiers.

Au lieu de cela, pour tout correctif dans l'entrée qui laisse un chemin (c'est-à-dire une non suppression) dans le résultat, nous vérifions tous les chemins principaux par rapport à l'arborescence résultante que le correctif créerait en inspectant tous les correctifs dans l'entrée, puis la cible du correctif l'application (soit l'index, soit l'arbre de travail).

De cette façon, nous:

  • attraper un méfait ou une erreur pour ajouter un lien symbolique path/to/diret un fichier path/to/dir/fileen même temps,
  • tout en autorisant un correctif valide qui supprime un symbole link path/to/dirpuis ajoute un fichier path/to/dir/file.

Cela signifie que, dans ce cas, le message d'erreur ne sera pas générique "%s: patch does not apply", mais plus spécifique:

affected file '%s' is beyond a symbolic link
VonC
la source
4

Hmmm, mount --bindne semble pas fonctionner sur Darwin.

Quelqu'un at-il une astuce qui le fait?

[édité]

OK, j'ai trouvé que la réponse sur Mac OS X est de créer un lien physique. Sauf que cette API n'est pas exposée via ln, vous devez donc utiliser votre propre petit programme pour ce faire. Voici un lien vers ce programme:

Création de liens matériels de répertoire sous Mac OS X

Prendre plaisir!

J Chris A
la source
1
Si le répertoire de destination de ce lien dur est un sous-répertoire d'un autre dépôt git, ce serait un chaos. Faire des opérations git dans le lien dur s'appliquerait à cet autre dépôt git. Vérifiez simplement ce que vous faites.
yegle
4
Il est possible de le faire via code.google.com/p/bindfs qui peut être installé à l'aide du port.
Kit Sunde
0

J'utilise Git 1.5.4.3 et il suit le lien symbolique passé s'il a une barre oblique. Par exemple

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Peter Mortensen
la source
5
au moins sur OSX, cela se traduit parfatal: 'src/' is beyond a symbolic link
Dan Rosenstark
2
Comme expliqué par @Mark Longair, cela n'a fonctionné que jusqu'au git 1.6.1
MestreLion
c'était mon problème, merci!
Mike Q
0

La conversion à partir de liens symboliques pourrait être utile. Lien dans un dossier Git au lieu d'un lien symbolique par un script .

Yurij73
la source
vous voulez ajouter plus de détails à votre réponse?
Devin G Rhode