windows git symlink

Git Symlinks en Windows



(11)

Nuestros desarrolladores utilizan una combinación de sistemas operativos basados ​​en Windows y Unix. Por lo tanto, los enlaces simbólicos creados en máquinas Unix se convierten en un problema para los desarrolladores de Windows. En Windows (msysgit), el enlace simbólico se convierte en un archivo de texto con una ruta al archivo al que apunta. En cambio, me gustaría convertir el enlace simbólico en un enlace simbólico real de Windows.

La solución ( actualizada ) que tengo para esto es:

  • Escriba un script post-checkout que buscará recursivamente los archivos de texto "symlink".
  • Reemplácelos con el enlace simbólico de Windows (usando mklink) con el mismo nombre y extensión que el "enlace simbólico" ficticio.
  • Ignore estos enlaces simbólicos de Windows al agregar una entrada en .git / info / exclude

No lo he implementado, pero creo que este es un enfoque sólido para este problema.

Preguntas:

  1. ¿Qué desventajas, si las hay, ve este enfoque?
  2. ¿Es este script post-checkout implementable? es decir, ¿puedo descubrir recursivamente los archivos ficticios "symlink" que crea git?
  3. ¿Alguien ha trabajado ya en ese guion?

Aquí hay un script por lotes para convertir enlaces simbólicos en el repositorio, solo para archivos, basado en la respuesta de Josh Lee. El script con algunos controles adicionales para los derechos de administrador se encuentra en https://gist.github.com/Quazistax/8daf09080bf54b4c7641 .

@echo off pushd "%~dp0" setlocal EnableDelayedExpansion for /f "tokens=3,*" %%e in (''git ls-files -s ^| findstr /R /C:"^120000"'') do ( call :processFirstLine %%f ) REM pause goto :eof :processFirstLine @echo. @echo FILE: %1 dir "%~f1" | find "<SYMLINK>" >NUL && ( @echo FILE already is a symlink goto :eof ) for /f "usebackq tokens=*" %%l in ("%~f1") do ( @echo LINK TO: %%l del "%~f1" if not !ERRORLEVEL! == 0 ( @echo FAILED: del goto :eof ) setlocal call :expandRelative linkto "%1" "%%l" mklink "%~f1" "!linkto!" endlocal if not !ERRORLEVEL! == 0 ( @echo FAILED: mklink @echo reverting deletion... git checkout -- "%~f1" goto :eof ) git update-index --assume-unchanged "%1" if not !ERRORLEVEL! == 0 ( @echo FAILED: git update-index --assume-unchanged goto :eof ) @echo SUCCESS goto :eof ) goto :eof :: param1 = result variable :: param2 = reference path from which relative will be resolved :: param3 = relative path :expandRelative pushd . cd "%~dp2" set %1=%~f3 popd goto :eof


Debería implementarse en msysgit, pero hay dos desventajas:

  • Los enlaces simbólicos solo están disponibles en Windows Vista y versiones posteriores (no debería ser un problema en 2011, y sin embargo es ...), ya que las versiones anteriores solo admiten uniones de directorio.
  • (el más grande) Microsoft considera que los enlaces simbólicos son un riesgo de seguridad y, por lo tanto, solo los administradores pueden crearlos de forma predeterminada. Deberá elevar los privilegios del proceso de git o usar fstool para cambiar este comportamiento en cada máquina en la que trabaje.

Hice una búsqueda rápida y se está trabajando activamente en esto, ver el número 224 .


Estaba buscando una solución fácil para tratar con los enlaces simbólicos de Unix en Windows. Muchas gracias por los alias de Git anteriores. Hay una pequeña optimización que se puede hacer con los rm-symlinks para que no elimine los archivos en la carpeta de destino en caso de que el alias se ejecute por segunda vez accidentalmente. Observe la nueva condición if en el ciclo para asegurarse de que el archivo no sea ya un enlace a un directorio antes de ejecutar la lógica.

git config --global alias.rm-symlinks ''!__git_rm_symlinks(){ for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do *if [ -d "$symlink" ]; then continue fi* git rm-symlink "$symlink" git update-index --assume-unchanged "$symlink" done }; __git_rm_symlinksenter


Estuve haciendo esta misma pregunta hace un tiempo (no aquí, solo en general) y terminé con una solución muy similar a la propuesta de OP. Primero, daré respuestas directas a las preguntas 1 2 y 3, y luego publicaré la solución que terminé usando.

  1. De hecho, hay algunas desventajas de la solución propuesta, principalmente con respecto a un mayor potencial de contaminación del repositorio, o la adición accidental de archivos duplicados mientras están en sus estados de "enlace simbólico de Windows". (Más sobre esto en "limitaciones" a continuación).
  2. Sí, ¡se puede implementar un script posterior a la compra! Tal vez no como un paso literal de git checkout posterior al git checkout , pero la solución a continuación ha cumplido mis necesidades lo suficientemente bien como para que no fuera necesario un script literal posterior a la salida.
  3. ¡Sí!

La solución:

Nuestros desarrolladores se encuentran en la misma situación que los OP''s: una mezcla de hosts basados ​​en Unix y Windows, repositorios y submódulos con muchos enlaces simbólicos git, y sin soporte nativo (todavía) en la versión de lanzamiento de MsysGit para manejar inteligentemente estos enlaces simbólicos en hosts Windows. .

Gracias a Josh Lee por señalar el hecho de que git comete enlaces simbólicos con el modo de archivo especial 120000 . Con esta información, es posible agregar algunos alias de git que permiten la creación y manipulación de enlaces simbólicos de git en los hosts de Windows.

  1. Creando enlaces simbólicos de git en Windows

    ACTUALIZADO 2014-11-12 (ver más abajo)

    git config --global alias.add-symlink ''!__git_add_symlink(){ argv=($@) argc=${#argv[@]} # Look for options options=(" -h") o_help="false" case "${argv[@]}" in *" -h"*) o_help="true" ;; esac if [ "$o_help" == "true" -o "$argc" -lt "2" ]; then echo "/ Usage: git add-symlink <target> <link> * <target> is a RELATIVE PATH, respective to <link>. * <link> is a RELATIVE PATH, respective to the repository''/'''s root dir. * Command must be run from the repository''/'''s root dir." return 0 fi target_arg=${argv[0]} link_arg=${argv[1]} if [ ! -e "$target_arg" ]; then echo "ERROR: Target $target_arg does not exist; not creating invalid symlink." return 1 fi hash=$(echo -n "$target_arg" | git hash-object -w --stdin) git update-index --add --cacheinfo 120000 "$hash" "$link_arg" git checkout -- "$link_arg" }; __git_add_symlink "$@"''

    Uso: git add-symlink <src> <dst> , donde <src> es una referencia relativa (con respecto a <dst> ) a la ubicación actual del archivo o directorio al que enlazarse, y <dst> es una referencia relativa (con respecto a la raíz del repositorio) al destino deseado del enlace.

    Por ejemplo, el árbol de repositorio:

    dir/ dir/foo/ dir/foo/bar/ dir/foo/bar/baz (file containing "I am baz") dir/foo/bar/lnk_file (symlink to ../../../file) file (file containing "I am file") lnk_bar (symlink to dir/foo/bar/)

    Se puede crear en Windows de la siguiente manera:

    git init mkdir -p dir/foo/bar/ echo "I am baz" > dir/foo/bar/baz echo "I am file" > file git add -A git commit -m "Add files" git add-symlink ../../../file dir/foo/bar/lnk_file git add-symlink dir/foo/bar/ lnk_bar git commit -m "Add symlinks"

  2. Sustitución de enlaces simbólicos git con enlaces duros NTFS + cruces

    git config --global alias.rm-symlink ''!__git_rm_symlink(){ git checkout -- "$1" link=$(echo "$1") POS=$''/'''/''/''' DOS=$''/'''////'/''' doslink=${link//$POS/$DOS} dest=$(dirname "$link")/$(cat "$link") dosdest=${dest//$POS/$DOS} if [ -f "$dest" ]; then rm -f "$link" cmd //C mklink //H "$doslink" "$dosdest" elif [ -d "$dest" ]; then rm -f "$link" cmd //C mklink //J "$doslink" "$dosdest" else echo "ERROR: Something went wrong when processing $1 . . ." echo " $dest may not actually exist as a valid target." fi }; __git_rm_symlink "$1"'' git config --global alias.rm-symlinks ''!__git_rm_symlinks(){ for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do git rm-symlink "$symlink" git update-index --assume-unchanged "$symlink" done }; __git_rm_symlinks''

    Uso:

    git rm-symlink dir/foo/bar/lnk_file git rm-symlink lnk_bar git update-index --assume-unchanged dir/foo/bar/lnk_file git update-index --assume-unchanged lnk_bar

    Esto elimina los enlaces simbólicos git uno a uno, reemplazándolos con enlaces duros NTFS (en el caso de los archivos) o uniones NTFS (en el caso de los directorios). El beneficio de usar enlaces duros y enlaces cruzados sobre enlaces simbólicos NTFS "verdaderos" es que no se requieren permisos elevados de UAC para poder crearlos. Finalmente, en su propio tiempo libre, puede elegir desmarcar-como-modificar (o no) los enlaces simbólicos "eliminados" con git update-index .

    Por conveniencia, también puede ejecutar:

    git rm-symlinks

    Esto elimina TODOS los enlaces simbólicos de git en el repositorio actual, reemplazándolos con enlaces cruzados + uniones según sea necesario, y marcando automáticamente los cambios para ser ignorados por el git status .

    Para eliminar los enlaces simbólicos de los submódulos, solo use el soporte integrado de git para iterar sobre ellos:

    git submodule foreach --recursive git rm-symlinks

    Pero, para cada acción drástica como esta, es agradable tener una reversión ...

  3. Restaurar enlaces simbólicos de git en Windows

    git config --global alias.checkout-symlinks ''!__git_checkout_symlinks(){ POS=$''/'''/''/''' DOS=$''/'''////'/''' for symlink in $(git ls-files -s | egrep "^120000" | cut -f2); do git update-index --no-assume-unchanged "$symlink" dossymlink=${symlink//$POS/$DOS} cmd //C rmdir //Q "$dossymlink" 2>/dev/null git checkout -- "$symlink" echo "Restored git symlink $symlink <<===>> $(cat $symlink)" done }; __git_checkout_symlinks''

    Uso: git checkout-symlinks , que deshace git rm-symlinks , restaurando efectivamente el repositorio a su estado natural (excepto por sus cambios, que deben permanecer intactos).

    Y para los submódulos:

    git submodule foreach --recursive git checkout-symlinks

  4. Limitaciones

    1. Solo se puede ejecutar desde la raíz del repositorio, de lo contrario, ocurre rareza ...
    2. La autocompletación basada en tabulaciones se rompe al escribir uno de estos alias
    3. Si las personas olvidan completar git checkout-symlinks antes de hacer algo como git add -A , ¡podrían contaminar el repositorio!

      Usando nuestro "informe repo" de antes:

      echo "I am nuthafile" > dir/foo/bar/nuthafile echo "Updating file" >> file git add -A git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: dir/foo/bar/nuthafile # modified: file # deleted: lnk_bar # POLLUTION # new file: lnk_bar/baz # POLLUTION # new file: lnk_bar/lnk_file # POLLUTION # new file: lnk_bar/nuthafile # POLLUTION #

      Whoops ...

      Por esta razón, es agradable incluir estos alias como pasos a realizar para usuarios de Windows antes y después de construir un proyecto, en lugar de después de finalizar la compra o antes de presionar. Pero cada situación es diferente. Estos alias me han sido lo suficientemente útiles como para que una verdadera solución posterior a la compra no haya sido necesaria.

¡Espero que ayude!

Referencias

http://git-scm.com/book/en/Git-Internals-Git-Objects

http://technet.microsoft.com/en-us/library/cc753194

ACTUALIZACIÓN 2014-11-12: dado que personalmente solo hice un uso intensivo de los rm-symlinks y checkout-symlinks alias de checkout-symlinks anteriores, logré pasar por alto un error bastante desagradable en el alias add-symlink . Anteriormente, -n no se pasaba a la declaración de echo responsable de crear el archivo de enlace simbólico git que luego se agregaría al área de ensayo como parte del funcionamiento de add-symlink . Esto significa que una nueva línea final ( 0x0D 0x0A en los hosts de Windows) se estaba agregando a todos los enlaces simbólicos creados con add-symlink . Si bien estos enlaces simbólicos de git seguirían siendo "removibles" en los hosts de Windows con rm-symlinks , si alguna vez se comprometieron con un repositorio público y luego clonados en un sistema genuino basado en posix, estos enlaces siempre saldrían rotos en el otro lado Este problema se ha solucionado y add-symlink ahora debería funcionar como se esperaba.


La versión más reciente de git scm (testet 2.11.1) permite habilitar enlaces simbólicos. Pero tienes que clonar el repositorio con los enlaces simbólicos otra vez git clone -c core.symlinks=true <URL> . Necesita ejecutar este comando con derechos de administrador. También es posible crear enlaces simbólicos en Windows con mklink. Mira la wiki .

wiki


Para quienes usan CygWin en Vista, Win7 o superior, el comando nativo git puede crear enlaces simbólicos "apropiados" que son reconocidos por aplicaciones de Windows como Android Studio . Solo necesita configurar la variable de entorno winsymlinks:native para incluir winsymlinks:native o winsymlinks:nativestrict como tal:

export CYGWIN="$CYGWIN winsymlinks:native"

La desventaja de esto (y una importante) es que el intérprete de CygWin debe ser "Ejecutar como administrador" para que tenga los permisos del sistema operativo necesarios para crear ese tipo de enlaces simbólicos. Una vez que se crean, sin embargo, no se requieren permisos especiales para usarlos . Siempre y cuando no sean cambiados en el repositorio por otro desarrollador, después de eso, git corre bien con los permisos de usuario normales.

Personalmente, uso esto solo para enlaces simbólicos que son navegados por aplicaciones de Windows (es decir, que no son CygWin) debido a esta dificultad adicional.

Para obtener más información sobre esta opción, consulte esta pregunta SO: Cómo hacer un enlace simbólico con cygwin en Windows 7


Respuesta corta: ahora son compatibles, si puedes habilitar el modo desarrollador.

Desde https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/

Ahora, en Windows 10 Creators Update, un usuario (con derechos de administrador) primero puede habilitar Developer Mode, y luego cualquier usuario de la máquina puede ejecutar el comando mklink sin elevar una consola de línea de comandos.

¿Qué impulsó este cambio? La disponibilidad y el uso de enlaces simbólicos es un gran problema para los desarrolladores modernos:

Muchas herramientas de desarrollo populares, como git y gestores de paquetes, como npm, reconocen y persisten los enlaces simbólicos al crear repositorios o paquetes, respectivamente. Cuando esos repos o paquetes se restauran en otro lugar, los enlaces simbólicos también se restauran, asegurando que el espacio en disco (y el tiempo del usuario) no se desperdicie.

Fácil de pasar por alto con todos los demás anuncios de la "Actualización del creador", pero si habilita el Modo desarrollador, puede crear enlaces simbólicos sin privilegios elevados. Es posible que tenga que volver a instalar y asegurarse de que la compatibilidad esté habilitada, ya que no está por defecto.


Sugeriría que no uses enlaces simbólicos dentro del repositorio ''. Almacene el contenido real dentro del repositorio y luego coloque los enlaces simbólicos al lado del repositorio que apunta al contenido.

Así que digamos que está utilizando un repositorio para comparar alojar su sitio en * nix con hosting en win. Almacene el contenido en su repositorio '', digamos /httpRepoContent y c:/httpRepoContent con esta es la carpeta que se sincroniza a través de GIT, SVN, etc.

Luego, reemplace la carpeta de contenido de su servidor web ( /var/www y c:/program files/web server/www {los nombres realmente no importan, edítelo si debe}) con un enlace simbólico al contenido de su repositorio ''. Los servidores web verán el contenido realmente en el lugar "correcto", pero usted puede usar su control de origen.

Sin embargo, si necesita utilizar enlaces simbólicos con en el repositorio, tendrá que buscar algo así como algún tipo de scripts de confirmación pre / post. Sé que puede usarlos para hacer cosas, como archivos de código parse a través de un formateador, por ejemplo, por lo que debería ser posible convertir los enlaces simbólicos entre plataformas.

si alguien conoce un buen lugar para aprender cómo hacer estos scripts para los controles fuente comunes, SVN GIT MG, entonces por favor agregue un comentario.


Un truco simple que usamos es simplemente llamar a git add -all dos veces seguidas.

Por ejemplo, nuestras llamadas de script de commit de Windows 7:

>git add -all >git add -all

El primer complemento trata el enlace como texto y agrega las carpetas para eliminar.

El segundo complemento atraviesa el enlace correctamente y deshace la eliminación restaurando los archivos.

Es menos elegante que algunas de las otras soluciones propuestas, pero es una solución simple para algunos de nuestros entornos heredados que agregaron enlaces simbólicos.


Utilizo enlaces sym todo el tiempo entre mi directorio raíz del documento y el directorio git repo. Me gusta mantenerlos separados. En Windows utilizo la opción mklink / j. La unión parece permitir que git se comporte normalmente:

>mklink /j <location(path) of link> <source of link>

por ejemplo:

>mklink /jc:/gitRepos/Posts C:/Bitnami/wamp/apache2/htdocs/Posts


Puede encontrar los enlaces simbólicos buscando archivos que tengan un modo de 120000 , posiblemente con este comando:

git ls-files -s | awk ''/120000/{print $4}''

Una vez que reemplace los enlaces, recomendaría marcarlos como sin cambios con git update-index --assume-unchanged , en lugar de enumerarlos en .git/info/exclude .