Como faço para o Git seguir os links simbólicos?

217

Meu melhor será um script de shell que substitua os links simbólicos por cópias, ou existe outra maneira de dizer ao Git para seguir os links simbólicos?

PS: Eu sei que não é muito seguro, mas só quero fazê-lo em alguns casos específicos.

Matt
fonte
5
existe uma desvantagem em usar links físicos para algo assim?
Ehtesh Choudhury
12
No Windows 7, "mklink / d" (link simbólico do diretório) não funciona com o git, mas "mklink / j" (juction) funciona bem.
yoyo
1
Se o arquivo for gerado automaticamente por um aplicativo que o regenere de maneira que exclua o arquivo e crie um novo, sim, esse é um problema que os hardlinks para os arquivos não resolverão.
Martin Pecka
1
@EhteshChoudhury você não pode criar links físicos para diretórios
Gaurav Kansal

Respostas:

46

NOTA: Este conselho está desatualizado de acordo com o comentário desde o Git 1.6.1. O Git costumava se comportar dessa maneira, e não o faz mais.


O Git, por padrão, tenta armazenar links simbólicos em vez de segui-los (por compacidade, e geralmente é o que as pessoas querem).

No entanto, acidentalmente, consegui que ele adicionasse arquivos além do link simbólico quando o link simbólico é um diretório.

Ou seja:

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

fazendo

 git add /bar/foo/baz

parecia funcionar quando eu tentei. No entanto, esse comportamento era indesejável para mim na época, então não posso fornecer informações além disso.

Kent Fredric
fonte
72
Os commits 725b06050a083474e240a2436121e0a80bb9f175 e 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 introduziram alterações que impediram a adição de arquivos além de diretórios com links simbólicos, portanto, isso não funcionará nas versões do git desde a versão 1.6.1
Mark Longair
1
$ git add src / main / path / ConvertSymlinkToDir fatal: 'src / main / path / ConvertSymlinkToDir' está além de um link simbólico
user1767316
2
@ user1767316 leu a coisa toda e os comentários. Costumava funcionar, não funciona mais. O software muda, mas as respostas aceitas pelo excesso de pilha não. Esclareci que isso ainda não funciona. Olhe para outra resposta.
Kent Fredric
yes @KentFrederic, mas escrever a mensagem de erro exata retornada ajuda a empilhar a pesquisa do usuário pela solução do seu problema. tentei cancelar o voto negativo, mas bloqueou desculpe. Por um lado, a sua resposta é direito dado o alerta, por outro um lado deve dar prioridade para responder a trabalhar agora, em vez do que no passado
user1767316
143

O que fiz para adicionar para obter os arquivos dentro de um link simbólico no Git (eu não usei um link simbólico, mas):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Execute este comando no diretório gerenciado pelo Git. TARGETDIRECTORYprecisa ser criado antes de o SOURCEDIRECTORYser montado nele.

Funciona bem no Linux, mas não no OS X! Esse truque também me ajudou com o Subversion. Eu o uso para incluir arquivos de uma conta do Dropbox, onde um webdesigner faz suas coisas.

user252400
fonte
8
Seria uma abordagem muito boa se o sudo não fosse necessário.
MestreLion
13
Para desfazer essa ligação, use umount [mydir]. (+1 para o seu grande dica, @ user252400)
JellicleCat
10
Isso funciona apenas durante a sessão. Qual é a melhor maneira de torná-lo "eterno"?
Adobe
17
@Adobe: colocá-lo em / etc / fstab, assim: / sourcedir / targetdir nenhum ligamento
Alexander Garden
8
O sshfs pode conseguir esse tipo de truque sem precisar do sudo, aqui.
PypeBros
75

Por que não criar links simbólicos de maneira inversa? Ou seja, em vez de vincular o repositório Git ao diretório do aplicativo, basta vincular o contrário.

Por exemplo, digamos que estou configurando um aplicativo instalado ~/applicationque precise de um arquivo de configuração config.conf:

  • Eu adiciono config.confao meu repositório Git, por exemplo, em ~/repos/application/config.conf.
  • Em seguida, crio um link simbólico ~/applicationexecutando ln -s ~/repos/application/config.conf.

Essa abordagem pode nem sempre funcionar, mas funcionou bem para mim até agora.

pináculo
fonte
5
Parece ser o único caminho, e não é tão ruim assim ... acho que o seu é uma abordagem bastante elegante. O git rastreia o conteúdo, não os arquivos. Então, mantendo todo o conteúdo em conjunto e criar um link simbólico de lá para outros lugares faz sentido
MestreLion
12
No meu caso, eu queria um link de um repositório git para outro, para poder editar arquivos em qualquer local e confirmar com seus respectivos controles remotos. No Windows 7, uma junção ("mklink / j") fez o truque.
yo-
3
claro. às vezes a resposta é simples assim.
BBW Antes do Windows
e se você quiser obter tanto a origem quanto o destino? (porque ambos pertencem a códigos diferentes que você quer ter em diferentes repositórios)
DrGC
1
Não responde à pergunta :( Eu queria que parte do meu repositório fosse sincronizada no meu iCloud. Infelizmente, o iCloud não segue links simbólicos, então pensei em fazer o git seguir os links simbólicos e armazenar arquivos originais no iCloud. symlinks: \
Jerry Green
49

Use links físicos. Isso difere de um link suave (simbólico). Todos os programas, inclusive git, tratarão o arquivo como um arquivo regular. Note que o conteúdo pode ser modificado alterando tanto a origem ou o destino.

No macOS (antes da 10.13 High Sierra)

Se você já possui o git e o Xcode instalados, instale o hardlink . É uma ferramenta microscópica para criar links físicos .

Para criar o link físico, basta:

hln source destination

atualização do macOS High Sierra

O Apple File System suporta links físicos de diretório?

Links físicos de diretório não são suportados pelo Apple File System. Todos os links físicos do diretório são convertidos em links simbólicos ou aliases quando você converte dos formatos de volume HFS + para APFS no macOS.

Das perguntas frequentes do APFS no developer.apple.com

Siga https://github.com/selkhateeb/hardlink/issues/31 para futuras alternativas.

No Linux e outros tipos de Unix

O lncomando pode criar links físicos:

ln source destination

No Windows (Vista, 7, 8,…)

Alguém sugeriu o uso do mklink para criar uma junção no Windows, mas eu não tentei:

mklink /j "source" "destination"
fregante
fonte
7
Apenas uma observação: isto é basicamente o que eu estava procurando, mas então eu aprendi que no Linux, infelizmente, um hardlink não pode cruzar os limites do sistema de arquivos (que é o meu caso de uso).
Sdaau
26
Você não pode conectar-se aos diretórios, pode?
Nanne
1
ln source destinationtambém funciona no OS X Testado em El Capitan.
Mahdi Dibaiee 04/12/2015
7
@Nanne não, mas você pode fazer: cp -al source destination. `-l 'significa arquivos de link físico em vez de copiar.
Paolo
6
Infelizmente, você não pode vincular diretórios, ou através dos limites do sistema de arquivos. Isso torna esta solução dupla inviável para mim.
Konrad Rudolph
25

Este é um gancho de pré-confirmação que substitui os blobs de link simbólico no índice pelo conteúdo desses links simbólicos.

Coloque isso .git/hooks/pre-commite torne-o executável:

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

Notas

Usamos a funcionalidade compatível com POSIX, tanto quanto possível; no entanto, diff -anão é compatível com POSIX, possivelmente entre outras coisas.

Pode haver alguns erros / erros neste código, mesmo que tenha sido testado um pouco.

Abbafei
fonte
4
É ótimo ver uma tentativa de responder à pergunta de arquivos e não de diretórios. No entanto, observe que o acima exposto ainda aparecerá typechangenos git statusarquivos que são realmente links simbólicos, embora o git agora seja o que não é.
David Fraser
1
Obrigado por isso; só queria saber o que é process_links_to_nondir?
Sdaau
@sdaau É o nome / argv[0]que é usado como o nome do comando para o shprocesso. (Levei um pouco para descobrir isso, já que eu não me lembro o que era ou ☺😃)
Abbafei
3
@Abbafei Você pode modificar o script para fazê-lo funcionar no Ubuntu (14.04)? Está mostrando find: missing argument to -exec'. Pode ser necessário executar um comando passo a passo em vez de canalizar e combinar tudo em uma única linha.
Khurshid Alam
1
@KhurshidAlam Para mim, trabalhou para remover as linhas comentadas entre as linhas de comando. No entanto, o gancho não funciona como esperado (eu recebo o typechangecomo @DavidFraser, mas o arquivo vinculado parece não ser encenado anymore)
SCz
14

Ativado MacOS(eu tenho o Mojave / 10.14, gitversão 2.7.1), use 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>

Isso foi sugerido por outros comentários, mas não claramente fornecido em outras respostas. Espero que isso economize tempo para alguém.

ijoseph
fonte
parece ótimo para as equipes que executam no Mac OS, acho que os links físicos descritos abaixo devem funcionar no Windows e no Linux.
Devin G Rhode
Isso foi útil e acho que a melhor solução para um recurso útil mas ausente no MacOS. Observe, no entanto, que eu estava recebendo Failed to resolve... No such file or directoryerros, a menos que eu usasse nomes de caminhos completos com o bindfscomando
electromaggot
Obrigado @electromaggot. Adicionado esclarecimento de que os caminhos completos são necessários
ijoseph 13/03
1
Funciona muito bem em macos Catalina!
Jerry Green
13

Eu costumava adicionar arquivos além dos links simbólicos há algum tempo. Isso costumava funcionar muito bem, sem fazer nenhum arranjo especial. Desde que atualizei para o Git 1.6.1, isso não funciona mais.

Você pode mudar para o Git 1.6.0 para fazer isso funcionar. Espero que uma versão futura do Git tenha um sinalizador para git-addpermitir que ele siga os links simbólicos novamente.

Erik Schnetter
fonte
12

Eu cansei de todas as soluções aqui desatualizadas ou exigindo root, por isso criei uma solução baseada em LD_PRELOAD (somente Linux).

Ele se prende aos internos do Git, substituindo o 'isso é um link simbólico?' , permitindo que os links simbólicos sejam tratados como seu conteúdo. Por padrão, todos os links para fora do repositório são incorporados; veja o link para detalhes.

Alcaro
fonte
Solução muito criativa usando LD_PRELOADpara substituir as funções da biblioteca!
iBug 20/05/19
Sim, mas deve ser elaborado aqui. Você pode fazer aquilo?
Peter Mortensen
Não tenho certeza de quanto elaboração ajudaria; a menos que eu copypaste o código fonte inteiro, esta resposta sempre dependerá desse link, onde também será possível encontrar um leia-me. Mas sim, acho que poderia reproduzir as partes importantes do leia-me.
Alcaro
Isso não é compilado no OS X (Mojave 10.14.2). Obtenha quatro erros reclamando sobre 'strchrnul' (você quis dizer 'strchr'?) E um sobre '__xstat64' (você quis dizer '__lxstat64'?). Finalmente, recebo um erro "acesso de membro ao tipo incompleto 'dirent64'". Acontece independentemente se eu usar "make", "make OPT = 1" ou "sh install.sh".
Erik Veland
@ErikVeland Eu tentei um pouco, mas parece que o OSX não suporta LD_PRELOAD, nem nada parecido. Vários documentos sugerem várias coisas, mas eles têm vários anos e a Apple adora depreciar coisas; Não consegui fazer nenhum deles funcionar. Desculpe.
Alcaro
6

Com o Git 2.3.2+ (primeiro trimestre de 2015), há outro caso em que o Git não segue mais o link simbólico: consulte commit e0d201b de Junio ​​C Hamano ( gitster) (principal mantenedor do Git)

apply: não toque em um arquivo além de um link simbólico

Como o Git rastreia links simbólicos como links simbólicos, um caminho que possui um link simbólico em sua parte principal (por exemplo path/to/dir/file, onde path/to/direxiste um link simbólico para outro lugar, seja dentro ou fora da árvore de trabalho) nunca pode aparecer em um patch que se aplica validamente , a menos que o mesmo patch remova primeiro o link simbólico para permitir que um diretório seja criado lá.

Detecte e rejeite esse patch.

Da mesma forma, quando uma entrada cria um link simbólico path/to/dire, em seguida, cria um arquivo path/to/dir/file, precisamos sinalizá-lo como um erro sem realmente criar path/to/dirum link simbólico no sistema de arquivos.

Em vez disso, para qualquer patch na entrada que deixe um caminho (ou seja, sem exclusão) no resultado, verificamos todos os caminhos iniciais na árvore resultante que o patch criaria, inspecionando todos os patches na entrada e depois o destino do patch aplicação (o índice ou a árvore de trabalho).

Dessa forma, nós:

  • pegar uma travessura ou um erro para adicionar um link simbólico path/to/dire um arquivo path/to/dir/fileao mesmo tempo,
  • enquanto permite um patch válido que remove um simbólico link path/to/dire adiciona um arquivo path/to/dir/file.

Isso significa que, nesse caso, a mensagem de erro não será genérica "%s: patch does not apply", mas mais específica:

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

Hmmm, mount --bindparece não funcionar em Darwin.

Alguém tem um truque que tem?

[editado]

OK, achei que a resposta no Mac OS X é criar um link físico. Exceto que essa API não é exposta via ln, você deve usar seu próprio programa minúsculo para fazer isso. Aqui está um link para esse programa:

Criando links físicos de diretório no Mac OS X

Aproveitar!

J Chris A
fonte
1
Se o diretório de destino desse hardlink for um subdiretório de outro repositório git, isso seria um caos. Executar operações git no hardlink se aplicaria a esse outro repositório git. Apenas verifique o que você está fazendo.
yegle
4
É possível fazer isso pelo code.google.com/p/bindfs, que pode ser instalado usando o port.
Kit Sunde 12/02
0

Estou usando o Git 1.5.4.3 e está seguindo o link simbólico passado, se houver uma barra final. Por exemplo

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Peter Mortensen
fonte
5
pelo menos no OSX isso resulta em:fatal: 'src/' is beyond a symbolic link
Dan Rosenstark
2
Como explicado por @ Marcos Longair, isso só funcionou até git 1.6.1
MestreLion
esse foi o meu problema, obrigado!
Mike Q
0

A conversão de links simbólicos pode ser útil. Vincule uma pasta Git em vez de um link simbólico por um script .

Yurij73
fonte
gostaria de adicionar mais detalhes à sua resposta?
Devin G Rhode