Come posso convincere Git a seguire i symlink?


217

Il mio meglio sarà uno script di shell che sostituisca i collegamenti simbolici con le copie o c'è un altro modo per dire a Git di seguire i collegamenti simbolici?

PS: So che non è molto sicuro, ma voglio farlo solo in alcuni casi specifici.


5
c'è uno svantaggio nell'utilizzare hard link per qualcosa del genere?
Ehtesh Choudhury,

12
Con Windows 7, "mklink / d" (collegamento simbolico alla directory) non funziona con git, ma "mklink / j" (juction) funziona bene.
yoyo

1
Se il file viene generato automaticamente da un'applicazione che lo rigenera in modo tale da eliminare il file e crearne uno nuovo, quindi sì, questo è un problema che i collegamenti fisici ai file non risolvono.
Martin Pecka,

1
@EhteshChoudhury non puoi creare hard link per le directory
Gaurav Kansal

Risposte:


46

NOTA: questo consiglio è ora obsoleto come da commento da Git 1.6.1. Git si comportava in questo modo e non lo fa più.


Git cerca di default di memorizzare i collegamenti simbolici invece di seguirli (per compattezza, ed è generalmente ciò che la gente vuole).

Tuttavia, sono riuscito accidentalmente a convincerlo ad aggiungere file oltre il collegamento simbolico quando il collegamento simbolico è una directory.

Vale a dire:

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

facendo

 git add /bar/foo/baz

sembrava funzionare quando l'ho provato. Quel comportamento era comunque indesiderato da me in quel momento, quindi non posso darti informazioni oltre a ciò.


72
I commit 725b06050a083474e240a2436121e0a80bb9f175 e 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 hanno introdotto modifiche che ti hanno impedito di aggiungere file oltre le directory symlinked, quindi questo non funzionerà nelle versioni di git
dall'1.6.1

1
$ git add src / main / path / ConvertSymlinkToDir fatale: 'src / main / path / ConvertSymlinkToDir' è oltre un collegamento simbolico
user1767316

2
@ user1767316 leggi tutto e i commenti. Funzionava, non funziona più. Il software cambia, ma le risposte accettate dallo stack-overflow no. Ho chiarito che non funziona già. Guarda un'altra risposta.
Kent Fredric,

sì @KentFrederic ma il richiamo dell'esatto messaggio di errore restituito aiuta a impilare la ricerca dell'utente per la soluzione al suo problema. Tentativo di annullare il downvote ma bloccato spiacente. Da un lato la tua risposta è corretta dato l'avvertimento, dall'altro dovrebbe dare la priorità alla risposta lavorando ora piuttosto che in passato
user1767316

143

Cosa ho fatto per aggiungere i file all'interno di un collegamento simbolico in Git (ma non ho usato un collegamento simbolico):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Esegui questo comando nella directory gestita da Git. TARGETDIRECTORYdeve essere creato prima del SOURCEDIRECTORYmontaggio.

Funziona bene su Linux, ma non su OS X! Quel trucco mi ha aiutato anche con Subversion. Lo uso per includere file da un account Dropbox, in cui un webdesigner fa le sue cose.


8
Sarebbe un approccio molto carino se sudo non fosse richiesto.
MestreLion,

13
Per annullare questa associazione, utilizzare umount [mydir]. (+1 per il tuo fantastico suggerimento, @ user252400)
JellicleCat

10
Funziona solo durante la sessione. Qual è il modo migliore per renderlo "eterno"?
Adobe,

17
@Adobe: inseriscilo in / etc / fstab, in questo modo: / sourcedir / targetdir none bind
Alexander Garden

8
sshfs può ottenere quel tipo di trucco senza richiedere il sudo, qui.
PypeBros,

75

Perché non creare collegamenti simbolici al contrario? Significa invece di collegare dal repository Git alla directory dell'applicazione, basta collegare il contrario.

Ad esempio, supponiamo che sto configurando un'applicazione installata in ~/applicationcui è necessario un file di configurazione config.conf:

  • Aggiungo config.confal mio repository Git, ad esempio, su ~/repos/application/config.conf.
  • Quindi creo un collegamento simbolico ~/applicationeseguendo ln -s ~/repos/application/config.conf.

Questo approccio potrebbe non funzionare sempre, ma finora ha funzionato bene per me.


5
Sembra essere l'unico modo, e non è poi così male ... penso che il tuo sia un approccio piuttosto elegante. git tiene traccia del contenuto, non dei file. Quindi ha senso tenere insieme tutti i contenuti e il collegamento simbolico da lì ad altri posti
MestreLion,

12
Nel mio caso, volevo un collegamento da un repository git a un altro, quindi posso modificare i file in entrambe le posizioni e tornare ai rispettivi telecomandi. Su Windows 7, una giunzione ("mklink / j") ha funzionato.
yoyo

3
ovviamente. a volte la risposta è così semplice.
BBW prima di Windows,

cosa succede se si desidera inserire sia la fonte che la destinazione? (perché entrambi appartengono a codici diversi che si desidera avere in repository diversi)
DrGC

1
Non risponde alla domanda :( Volevo che parte del mio repository venisse sincronizzata con il mio iCloud. Sfortunatamente, iCloud non segue i collegamenti simbolici, quindi ho pensato di fare in modo che Git seguisse i collegamenti simbolici e archiviare i file originali in iCloud. symlink: \
Jerry Green

49

Utilizzare invece i collegamenti reali. Ciò differisce da un collegamento soft (simbolico). Tutti i programmi, incluso gittratteranno il file come un file normale. Si noti che i contenuti possono essere modificati cambiando sia l'origine o la destinazione.

Su macOS (prima delle 10.13 High Sierra)

Se hai già installato git e Xcode, installa hardlink . È uno strumento microscopico per creare collegamenti reali .

Per creare il collegamento reale, semplicemente:

hln source destination

aggiornamento macOS High Sierra

Il file system Apple supporta i collegamenti hard della directory?

I collegamenti diretti alle directory non sono supportati dal file system Apple. Tutti i collegamenti diretti alla directory vengono convertiti in collegamenti simbolici o alias quando si converte da HFS + in formati di volume APFS su macOS.

Dalle domande frequenti su APFS su developer.apple.com

Segui https://github.com/selkhateeb/hardlink/issues/31 per alternative future.

Su Linux e altri tipi di Unix

Il lncomando può creare collegamenti reali:

ln source destination

Su Windows (Vista, 7, 8, ...)

Qualcuno ha suggerito di usare mklink per creare un nodo su Windows, ma non l'ho provato:

mklink /j "source" "destination"

7
Solo una nota: questo è fondamentalmente quello che stavo cercando, ma poi ho imparato che su Linux, sfortunatamente, un hardlink non può oltrepassare i confini del filesystem (che è il mio caso d'uso).
sdaau,

26
Non puoi collegarti direttamente alle directory, vero?
Nanne,

1
ln source destinationfunziona anche in OS X. Testato su El Capitan.
Mahdi Dibaiee il

7
@Nanne no, ma si può fare: cp -al source destination. `-l 'significa file con collegamento reale anziché copia.
Paolo

6
Sfortunatamente non è possibile creare collegamenti hard-link o oltre i limiti del file system. Questo rende questa soluzione duplice per me non realizzabile.
Konrad Rudolph,

25

Questo è un hook pre-commit che sostituisce i BLOB di link simbolici nell'indice, con il contenuto di tali link simbolici.

Inseriscilo .git/hooks/pre-commite rendilo eseguibile:

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

Appunti

Utilizziamo la funzionalità conforme POSIX il più possibile; tuttavia, diff -anon è conforme a POSIX, probabilmente tra le altre cose.

Potrebbero esserci alcuni errori / errori in questo codice, anche se è stato testato in qualche modo.


4
È bello vedere un tentativo di rispondere effettivamente alla domanda per i file e non per le directory. Si noti tuttavia che quanto sopra mostrerà ancora typechangein git statusper i file che sono in realtà i collegamenti simbolici se git ora le cose non lo sono.
David Fraser,

1
Grazie per questo; volevo solo sapere, cos'è process_links_to_nondir?
sdaau,

@sdaau È il nome / argv[0]che viene utilizzato come nome-comando per il shprocesso. (Mi ha preso un po 'per capirlo, dal momento che non ricordavo nemmeno cosa fosse ☺😃)
Abbafei,

3
@Abbafei Puoi modificare lo script per farlo funzionare su Ubuntu (14.04)? Sta mostrando find: missing argument to -exec'. Potrebbe essere necessaria l'esecuzione di un comando passo dopo passo invece di eseguire il piping e combinare tutto in un'unica riga.
Khurshid Alam,

1
@KhurshidAlam Per me ha funzionato per rimuovere le righe commentate tra le righe di comando. Tuttavia, l'hook non funziona come previsto (ottengo il typechangetipo @DavidFraser, ma il file collegato sembra non essere più messo in scena)
Scz

14

MacOS(ho Mojave / 10.14, gitversione 2.7.1), utilizzare 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>

È stato suggerito da altri commenti, ma non è stato chiaramente fornito in altre risposte. Spero che questo faccia risparmiare tempo a qualcuno.


sembra ottimo per i team che girano tutti su Mac OS, penso che i collegamenti reali descritti di seguito dovrebbero funzionare per Windows e Linux.
Devin G Rhode,

Questo è stato utile e penso che sia la soluzione migliore per una funzionalità utile ma mancante in MacOS. Nota comunque che stavo ottenendo Failed to resolve... No such file or directoryerrori a meno che non avessi usato i nomi di percorso completi con il bindfscomando.
electromaggot

Grazie @elettromaggot. Aggiunto chiarimento che sono necessari percorsi completi
ijoseph

1
Funziona alla grande su macos Catalina!
Jerry Green

13

Da un po 'di tempo aggiungevo file oltre i link simbolici. In passato funzionava perfettamente, senza prendere accordi speciali. Da quando ho aggiornato a Git 1.6.1, questo non funziona più.

Potresti essere in grado di passare a Git 1.6.0 per farlo funzionare. Spero che una versione futura di Git abbia una bandiera che git-addconsenta di seguire di nuovo i symlink.


12

Mi sono stancato di ogni soluzione qui obsoleta o che richiedeva root, quindi ho creato una soluzione basata su LD_PRELOAD (solo Linux).

Si aggancia agli interni di Git, sovrascrivendo "è questo un link simbolico?" funzione, che consente ai symlink di essere trattati come i loro contenuti. Per impostazione predefinita, tutti i collegamenti all'esterno del repository sono in linea; vedere il link per i dettagli.


Soluzione molto creativa che utilizza LD_PRELOADper sovrascrivere le funzioni di libreria!
iBug

Sì, ma dovrebbe essere elaborato qui. Puoi farlo?
Peter Mortensen,

Non sono sicuro di quanta elaborazione possa aiutare; a meno che non copio l'intero codice sorgente, questa risposta si baserà sempre su quel link, dove è anche possibile trovare un file Leggimi. Ma sì, immagino di poter riprodurre le parti importanti del readme.
Alcaro,

Questo non viene compilato su OS X (Mojave 10.14.2). Ricevi quattro errori che si lamentano di "strchrnul" (intendevi "strchr"?) E uno di "__xstat64" (intendevi "__lxstat64"?). Finalmente ottengo un errore "accesso membro in tipo incompleto 'dirent64'". Succede a prescindere se uso "make", "make OPT = 1" o "sh install.sh".
Erik Veland,

@ErikVeland Ho provato un po ', ma sembra che OSX non supporti LD_PRELOAD, né nulla di simile. Vari documenti suggeriscono varie cose, ma hanno tutti diversi anni e Apple ama deprecare le cose; Non riuscivo a far funzionare nessuno di loro. Scusate.
Alcaro

6

Con Git 2.3.2+ (Q1 2015), c'è un altro caso in cui Git non seguirà più il collegamento simbolico: vedi commit e0d201b di Junio ​​C Hamano ( gitster) (manutentore principale di Git)

apply: non toccare un file oltre un collegamento simbolico

Poiché Git tiene traccia dei collegamenti simbolici come collegamenti simbolici, un percorso che ha un collegamento simbolico nella sua parte principale (ad esempio path/to/dir/file, dove si path/to/dirtrova un collegamento simbolico verso un altro luogo, all'interno o all'esterno dell'albero di lavoro) non può mai apparire in una patch che si applica validamente , a meno che la stessa patch non rimuova prima il collegamento simbolico per consentire la creazione di una directory lì.

Rileva e rifiuta una tale patch.

Allo stesso modo, quando un input crea un collegamento simbolico path/to/dire quindi crea un file path/to/dir/file, dobbiamo contrassegnarlo come errore senza effettivamente creare path/to/dirun collegamento simbolico nel filesystem.

Invece, per qualsiasi patch nell'input che lascia un percorso (cioè una non cancellazione) nel risultato, controlliamo tutti i percorsi principali rispetto all'albero risultante che la patch creerebbe controllando tutte le patch nell'input e quindi la destinazione della patch applicazione (l'indice o l'albero di lavoro).

In questo modo, noi:

  • intercettare un errore o un errore per aggiungere contemporaneamente un collegamento simbolico path/to/dire un file path/to/dir/file,
  • pur consentendo una patch valida che rimuove un simbolico link path/to/dire quindi aggiunge un file path/to/dir/file.

Ciò significa che, in tal caso, il messaggio di errore non sarà simile a un generico "%s: patch does not apply", ma più specifico:

affected file '%s' is beyond a symbolic link

4

Hmmm, mount --bindnon sembra funzionare su Darwin.

Qualcuno ha un trucco che ha?

[modificato]

OK, ho trovato la risposta su Mac OS X è quella di creare un collegamento reale. Solo che l'API non è esposta tramite ln, quindi devi usare il tuo piccolo programma per farlo. Ecco un link a quel programma:

Creazione di collegamenti hard directory in Mac OS X.

Godere!


1
Se la directory di destinazione di questo hardlink è una sottodirectory di un altro repository git, questo sarebbe un caos. Fare operazioni git nel collegamento fisico si applicherebbe a questo altro repository git. Basta ricontrollare quello che stai facendo.
yegle,

4
È possibile farlo tramite code.google.com/p/bindfs che può essere installato utilizzando la porta.
Kit Sunde,

0

Sto usando Git 1.5.4.3 e sta seguendo il link simbolico passato se ha una barra finale. Per esempio

# Adds the symlink itself
$ git add symlink

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

5
almeno su OSX questo si traduce infatal: 'src/' is beyond a symbolic link
Dan Rosenstark,

2
Come spiegato da @Mark Longair, questo ha funzionato solo fino a git 1.6.1
MestreLion,

quello era il mio problema, grazie!
Mike Q,

0

La conversione da symlink potrebbe essere utile. Collegamento in una cartella Git invece di un collegamento simbolico di uno script .


Vuoi aggiungere maggiori dettagli alla tua risposta?
Devin G Rhode,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.