Como o Git lida com links simbólicos?

1607

Se eu tenho um arquivo ou diretório que é um link simbólico e o comprometo em um repositório Git, o que acontece com ele?

Eu diria que ele deixa como um link simbólico até que o arquivo seja excluído e, se você retirar o arquivo de uma versão antiga, ele criará um arquivo normal.

O que faz quando eu excluo o arquivo que ele faz referência? Apenas confirma o link pendente?

Alex
fonte
19
.gitignorevê o link simbólico como um arquivo, não uma pasta.
0xcaff
6
Bem, evidentemente, há mais na pergunta do que essa resposta implica. Por exemplo, estou me perguntando o seguinte: se eu criar um link sym no meu repositório para algum arquivo grande nesse repositório, enviar as alterações por push e depois puxá-las para outra máquina, o que acontecerá? O arquivo grande será armazenado como um arquivo grande nos dois locais ou o link sym será preservado, de modo que, na nova máquina, o arquivo de link aponte para o arquivo grande original?
jvriesem
7
Este é um tópico antigo, mas esse comentário ainda pode ser útil. Em resposta ao jviesem, um link flexível é basicamente um arquivo com o nome de outro arquivo. Portanto, quando você o puxar para uma máquina diferente, o link será baixado e terá o nome do arquivo grande no sistema de arquivos original. Se na nova máquina o nome não for válido, o link terá um nome inválido. O arquivo grande não será baixado para a nova máquina.
Lasaro
6
@lasaro, a maneira de evitar links quebrados em um repositório git é sempre usar caminhos relativos ao criar os links simbólicos, usando ../..conforme necessário.
Curinga
8
Observe que na maioria das versões do Windows você precisa de permissões elevadas para criar um link simbólico. Se você estiver no Windows e git pullcriar um arquivo em vez de um link simbólico, tente executar o seu cliente Git como administrador.
axmrnv

Respostas:

1348

O Git apenas armazena o conteúdo do link (ou seja, o caminho do objeto do sistema de arquivos ao qual ele se vincula) em um 'blob', como faria em um arquivo normal. Em seguida, ele armazena o nome, o modo e o tipo (incluindo o fato de ser um link simbólico) no objeto em árvore que representa o diretório que o contém.

Quando você faz check-out de uma árvore que contém o link, ele restaura o objeto como um link simbólico, independentemente de o objeto do sistema de arquivos de destino existir ou não.

Se você excluir o arquivo ao qual o link simbólico faz referência, ele não afetará o link simbólico controlado pelo Git. Você terá uma referência pendente. Cabe ao usuário remover ou alterar o link para apontar para algo válido, se necessário.

CB Bailey
fonte
328
Entre. Se você estiver em um sistema de arquivos como o FAT que não suporta links simbólicos e o seu repositório os usar, poderá definir a core.symlinksvariável de configuração como false, e os links simbólicos serão verificados como pequenos arquivos de texto sem formatação que contêm o texto do link.
Jakub Narębski
14
@ JakubNarębski Eu vi isso antes. Havia um arquivo de texto em nosso repositório com uma linha, um caminho para uma biblioteca que usamos. Não conseguia descobrir qual era o objetivo disso. Eu sei agora o que aconteceu.
Matt K
25
Hesito em comentar sobre uma resposta altamente votada, mas acho que a expressão "como seria para um arquivo normal" pode ser enganosa para os recém-chegados.
Matthew Hannigan
10
(ficou sem tempo de edição) É como um arquivo normal, apenas porque o conteúdo está em um blob. A diferença crítica é que, para um arquivo normal, o blob é o conteúdo do arquivo, mas para um link simbólico, o blob possui o nome do caminho do arquivo ao qual ele vincula. @ JakubNarębski Com relação a "pequenos arquivos de texto simples" .. Você esperaria que eles fossem pequenos e de texto, mas é claro que um blob é um blob e potencialmente pode ser enorme e binário. Consulte stackoverflow.com/questions/18411200/… para saber quando um arquivo está digitado incorretamente como um link simbólico.
Matthew Hannigan
2
Verifique as configurações globais para links simbólicos e as configurações locais para links simbólicos. Se as configurações foram copiadas do TortiseGit ou do Windows, você pode estar symlinks = falsemexendo com elas.
phyatt
250

Você pode descobrir o que o Git faz com um arquivo, vendo o que ele faz quando o adiciona ao índice. O índice é como um pré-commit. Com o índice confirmado, você pode usar git checkoutpara trazer tudo o que estava no índice de volta ao diretório de trabalho. Então, o que o Git faz quando você adiciona um link simbólico ao índice?

Para descobrir, primeiro, faça um link simbólico:

$ ln -s /path/referenced/by/symlink symlink

O Git ainda não sabe sobre esse arquivo. git ls-filespermite inspecionar seu índice ( saída semelhante a -simpressões stat):

$ git ls-files -s ./symlink
[nothing]

Agora, adicione o conteúdo do link simbólico ao armazenamento de objetos Git, adicionando-o ao índice. Quando você adiciona um arquivo ao índice, o Git armazena seu conteúdo no armazenamento de objetos Git.

$ git add ./symlink

Então, o que foi adicionado?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink

O hash é uma referência ao objeto compactado que foi criado no armazenamento de objetos Git. Você pode examinar esse objeto se procurar na .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15craiz do seu repositório. Este é o arquivo que o Git armazena no repositório, que você pode conferir posteriormente. Se você examinar esse arquivo, verá que ele é muito pequeno. Não armazena o conteúdo do arquivo vinculado.

(Note 120000é o modo listado na ls-filessaída. Seria como 100644um arquivo normal.)

Mas o que o Git faz com esse objeto quando você faz o check-out do repositório e do seu sistema de arquivos? Depende da core.symlinksconfiguração. De man git-config:

core.symlinks

Se falso, os links simbólicos são retirados como pequenos arquivos simples que contêm o texto do link.

Portanto, com um link simbólico no repositório, no check-out, você obtém um arquivo de texto com uma referência a um caminho completo do sistema de arquivos ou um link simbólico adequado, dependendo do valor da core.symlinksconfiguração.

De qualquer forma, os dados referenciados pelo link simbólico não são armazenados no repositório.

Dmitry Minkovsky
fonte
1
Ótima
147

Nota do "editor": esta postagem pode conter informações desatualizadas. Por favor, veja os comentários e esta pergunta sobre as mudanças no Git desde 1.6.1.

Diretórios com links simbólicos:

É importante observar o que acontece quando há um diretório que é um link direto. Qualquer pull do Git com uma atualização remove o link e o torna um diretório normal. Isto é o que eu aprendi da maneira mais difícil. Algumas idéias aqui e aqui.

Exemplo

Antes

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir

git add/commit/push

It remains the same

Depois git pullE algumas atualizações encontradas

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir
Shekhar
fonte
4
Vale a pena notar que esses avisos sobre diretórios com links simbólicos não se aplicam a links simbólicos com versão. O principal problema em questão foi o de pessoas vinculando parte ou a totalidade da árvore de trabalho em um caminho diferente (digamos em uma partição diferente com mais espaço em disco) e esperando que o git verifique o código através do link simbólico existente. Ou seja, se você tiver um projeto que contém links simbólicos com versão para arquivos ou diretórios, o comportamento normal do link simbólico como blob preservará os links simbólicos, a versão correta das alterações nesses links simbólicos e funcionará conforme o esperado.
John Whitley
O comportamento acima testado com git 1.6.5.6; mas suspeito fortemente que o comportamento de versão esteja correto no git há algum tempo.
John Whitley
22
Esse comportamento está presente em todas as versões do git ou foi corrigido?
Jbotnik
24
Parece que este comportamento é corrigido agora, veja: stackoverflow.com/a/1943656/1334781
Ron Wertlen
2
Shekar: Você editará sua resposta para refletir as mudanças no git nos últimos anos?
einpoklum