¿Cómo maneja Git los enlaces simbólicos?

1607

Si tengo un archivo o directorio que es un enlace simbólico y lo envío a un repositorio de Git, ¿qué le sucede?

Supongo que lo deja como un enlace simbólico hasta que se elimine el archivo y luego, si retira el archivo de una versión anterior, simplemente crea un archivo normal.

¿Qué hace cuando borro el archivo al que hace referencia? ¿Solo compromete el enlace colgante?

Alex
fuente
19
.gitignoreve el enlace simbólico como un archivo, no como una carpeta.
0xcaff
66
Bueno, evidentemente hay más en la pregunta de lo que implica esa respuesta. Por ejemplo, me pregunto lo siguiente: si creo un enlace simétrico en mi repositorio a algún archivo grande en ese repositorio, empujo los cambios y luego empujo esos cambios a otra máquina, ¿qué sucederá? ¿Se almacenará el archivo grande como un archivo grande en ambas ubicaciones, o se conservará el enlace simétrico, de modo que en la nueva máquina, el archivo de enlace apunte al archivo grande original?
jvriesem
77
Este es un hilo antiguo pero este comentario aún puede ser útil. En respuesta a jviesem, un enlace suave es básicamente un archivo con el nombre de otro archivo. Entonces, una vez que lo coloque en una máquina diferente, el enlace se descargará y tendrá el nombre del archivo grande en el sistema de archivos original. Si en la nueva máquina el nombre no es válido, entonces el enlace tendrá un nombre no válido. El archivo grande no se descargará a la nueva máquina.
lasaro
66
@lasaro, la forma de evitar enlaces rotos en un repositorio de git es usar siempre rutas relativas al hacer los enlaces simbólicos, utilizando ../..según sea necesario.
Comodín el
8
Tenga en cuenta que en la mayoría de las versiones de Windows necesita permisos elevados para crear un enlace simbólico. Si está en Windows y git pullcrea un archivo en lugar de un enlace simbólico, intente ejecutar su cliente Git como administrador.
axmrnv

Respuestas:

1347

Git simplemente almacena el contenido del enlace (es decir, la ruta del objeto del sistema de archivos al que se vincula) en un 'blob' tal como lo haría para un archivo normal. Luego almacena el nombre, modo y tipo (incluido el hecho de que es un enlace simbólico) en el objeto de árbol que representa su directorio contenedor.

Cuando desprotege un árbol que contiene el enlace, restaura el objeto como un enlace simbólico, independientemente de si el objeto del sistema de archivos de destino existe o no.

Si elimina el archivo al que hace referencia el enlace simbólico, no afecta de ninguna manera al enlace simbólico controlado por Git. Tendrás una referencia colgante. Depende del usuario eliminar o cambiar el enlace para señalar algo válido si es necesario.

CB Bailey
fuente
328
Por cierto. Si está en un sistema de archivos como FAT que no admite enlaces simbólicos, y su repositorio los usa, puede establecer la core.symlinksvariable de configuración en falso, y los enlaces simbólicos se verían como pequeños archivos de texto sin formato que contienen el texto del enlace.
Jakub Narębski
14
@ JakubNarębski Vi esto antes. Había un archivo de texto en nuestro repositorio con una línea, una ruta a una biblioteca que usamos. No pude averiguar cuál era el propósito. Ahora sé lo que pasó.
Matt K
25
Dudo en comentar sobre una respuesta altamente votada, pero creo que la frase "al igual que lo haría para un archivo normal" podría ser engañosa para los recién llegados.
Matthew Hannigan el
10
(se acabó el tiempo de edición) Es como un archivo normal solo porque el contenido está en un blob. La diferencia crítica es que, para un archivo normal, el blob es el contenido del archivo, pero para un enlace simbólico, el blob tiene la ruta del archivo al que está vinculado. @ JakubNarębski Con respecto a los "pequeños archivos de texto sin formato". Es de esperar que sean pequeños y de texto, pero, por supuesto, un blob es un blob y potencialmente podría ser enorme y binario. Consulte stackoverflow.com/questions/18411200/… para saber cuándo un archivo está mal escrito como un enlace simbólico.
Matthew Hannigan el
2
Asegúrese de verificar su configuración global para enlaces simbólicos y la configuración local para enlaces simbólicos. Si las configuraciones se copiaron desde TortiseGit o Windows, entonces podría haber tenido problemas symlinks = falsecon ellas.
phyatt
251

Puede averiguar qué hace Git con un archivo al ver qué hace cuando lo agrega al índice. El índice es como una confirmación previa. Con el índice comprometido, puede usar git checkoutpara traer todo lo que estaba en el índice nuevamente al directorio de trabajo. Entonces, ¿qué hace Git cuando agrega un enlace simbólico al índice?

Para averiguarlo, primero, haga un enlace simbólico:

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

Git aún no conoce este archivo. git ls-filesle permite inspeccionar su índice ( -simpresiones statcomo salida):

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

Ahora, agregue el contenido del enlace simbólico al almacén de objetos Git agregándolo al índice. Cuando agrega un archivo al índice, Git almacena su contenido en el almacén de objetos de Git.

$ git add ./symlink

Entonces, ¿qué se agregó?

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

El hash es una referencia al objeto empaquetado que se creó en el almacén de objetos Git. Puede examinar este objeto si busca .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15cen la raíz de su repositorio. Este es el archivo que Git almacena en el repositorio, que luego puede consultar. Si examina este archivo, verá que es muy pequeño. No almacena el contenido del archivo vinculado.

(Tenga en 120000cuenta que el modo aparece en la ls-filessalida. Sería algo así como 100644para un archivo normal).

Pero, ¿qué hace Git con este objeto cuando lo revisa desde el repositorio y lo ingresa a su sistema de archivos? Depende de la core.symlinksconfiguración. De man git-config:

core.symlinks

Si es falso, los enlaces simbólicos se verifican como pequeños archivos sin formato que contienen el texto del enlace.

Entonces, con un enlace simbólico en el repositorio, al finalizar la compra, obtiene un archivo de texto con una referencia a una ruta completa del sistema de archivos, o un enlace simbólico adecuado, dependiendo del valor de la core.symlinksconfiguración.

De cualquier manera, los datos a los que hace referencia el enlace simbólico no se almacenan en el repositorio.

Dmitry Minkovsky
fuente
1
Excelente respuesta
CervEd
147

Nota del "Editor": esta publicación puede contener información desactualizada. Consulte los comentarios y esta pregunta sobre los cambios en Git desde 1.6.1.

Directorios con enlaces simbólicos:

Es importante tener en cuenta lo que sucede cuando hay un directorio que es un enlace suave. Cualquier extracción de Git con una actualización elimina el enlace y lo convierte en un directorio normal. Esto es lo que aprendí de manera difícil. Algunas ideas aquí y aquí.

Ejemplo

antes de

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

git add/commit/push

It remains the same

Después git pullY algunas actualizaciones encontradas

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir
Shekhar
fuente
44
Vale la pena señalar que estas advertencias sobre directorios con enlaces simbólicos no se aplican a los enlaces simbólicos versionados. El principal caso en cuestión fue el de la gente que simboliza parte o la totalidad del árbol de trabajo en una ruta diferente (por ejemplo, en una partición diferente con más espacio en disco) y esperaba que git revisara el código a través del enlace simbólico existente. Es decir, si tiene un proyecto que contiene enlaces simbólicos versionados a archivos o directorios, el comportamiento normal de enlace simbólico como blob conservará los enlaces simbólicos, los cambios de versión correctos a esos enlaces simbólicos y, de lo contrario, funcionará como se esperaba.
John Whitley
El comportamiento anterior probado con git 1.6.5.6; pero sospecho firmemente que el comportamiento versionado ha sido correcto en git durante bastante tiempo.
John Whitley
22
¿Este comportamiento está presente en todas las versiones de git o se ha solucionado?
jbotnik
24
Parece que este comportamiento está solucionado ahora, consulte: stackoverflow.com/a/1943656/1334781
Ron Wertlen
2
Shekar: ¿Editarás tu respuesta para reflejar los cambios en git en los últimos años?
einpoklum