Символические ссылки Git в Windows

наши разработчики используют сочетание ОС на базе Windows и Unix. Поэтому символические ссылки, созданные на машинах Unix, становятся проблемой для разработчиков Windows. В Windows (msysgit), символическая ссылка преобразуется в текстовый файл с путем к файлу, на который он указывает. Вместо этого я хотел бы преобразовать символическую ссылку в фактическую символическую ссылку Windows.

The (обновлено) решение у меня такое:

  • напишите сценарий post-checkout, который будет рекурсивно искать " символическую ссылку" текстовый файл.
  • замените их символической ссылкой windows (используя mklink) с тем же именем и расширением, что и фиктивная "символическая ссылка"
  • игнорировать эти окна символическую ссылку, добавив вступление .git/info / exclude

Я не реализовал это, но я считаю, что это солидный подход к этой проблеме.

вопросы:

  1. какие минусы вы видите в таком подходе?
  2. этот сценарий после проверки даже реализуем? т. е. я могу рекурсивно узнайте манекен "ссылка" файлы git создает?
  3. кто-нибудь уже работал по такому сценарию?

12 ответов


вы можете найти символические ссылки, ища файлы, которые имеют режим 120000, возможно, с помощью этой команды:

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

как только вы замените ссылки, я бы рекомендовал пометить их как неизменные с git update-index --assume-unchanged, а не перечислять их в .git/info/exclude.


я задавал этот же самый вопрос некоторое время назад (не здесь, просто в целом) и в конечном итоге придумал очень похожее решение предложения OP. Сначала я дам прямые ответы на вопросы 1 2 & 3, а затем опубликую решение, которое я использовал.

  1. в предлагаемом решении действительно есть несколько недостатков, в основном связанных с повышенным потенциалом загрязнения хранилища или случайного добавления дубликатов файлов, пока они находятся в своих " окнах ссылка" государства. (Подробнее об этом в разделе "Ограничения" ниже.)
  2. да, сценарий после проверки реализован! Может быть, не как буквальный пост -git checkout шаг, но решение ниже удовлетворяло мои потребности достаточно хорошо, чтобы буквальный сценарий после проверки не был необходим.
  3. да!

Решение:

наши разработчики находятся в той же ситуации, что и OP: смесь хостов Windows и Unix, репозиториев и подмодулей со многими git символические ссылки и отсутствие собственной поддержки (пока) в версии MsysGit для разумной обработки этих символических ссылок на узлах Windows.

спасибо Джошу ли за указание на то, что git фиксирует символические ссылки со специальным filemode 120000. С помощью этой информации можно добавить несколько псевдонимов git, которые позволяют создавать и манипулировать символическими ссылками git на узлах Windows.

  1. создание символических ссылок git на Окна

    обновление 2014-11-12 (см. ниже)

    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 "$@"'
    

    использование: git add-symlink <src> <dst>, где <src> это относительная ссылка (в отношении <dst>) к текущему местоположению файла или каталога для ссылки и <dst> это относительная ссылка (относительно корня репозитория) к месту назначения ссылки.

    Е. Г., дерево репозитория:

    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/)
    

    может быть создал в Windows следующим образом:

    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. замена символических ссылок git на жесткие ссылки NTFS+соединения

    git config --global alias.rm-symlink '!__git_rm_symlink(){
        git checkout -- ""
        link=$(echo "")
        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  . . ."
            echo "       $dest may not actually exist as a valid target."
        fi
    }; __git_rm_symlink ""'
    
    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'
    

    использование:

    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
    

    это удаляет символические ссылки git один за другим, заменяя их жесткими ссылками NTFS (в случае файлов) или соединениями NTFS (в случае каталогов). Преимущества использования жестких ссылок+Спаи за "правдой" в NTFS симлинки это повышенные разрешения UAC не требуются для их нужно создать. наконец, на досуге вы можете выбрать unflag-as-modified (или нет) "удаленные" символические ссылки с git update-index.

    для удобства, вы также можете просто запустить:

    git rm-symlinks
    

    это удаляет все символические ссылки git в текущем репозитории, заменяя их жесткими ссылками+соединениями по мере необходимости и автоматически помечая изменения, которые будут игнорироваться git status.

    чтобы удалить символические ссылки из подмодулей, просто используйте встроенная поддержка Git для итерации над ними:

    git submodule foreach --recursive git rm-symlinks
    

    но, для каждого радикального действия, как это, разворот приятно иметь...

  3. восстановление символических ссылок git в 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'
    

    использование: git checkout-symlinks, который отменяет git rm-symlinks, эффективно восстанавливая репозиторий в его естественное состояние (за исключением ваших изменений, которые должны остаются нетронутыми).

    и подмодули:

    git submodule foreach --recursive git checkout-symlinks
    
  4. ограничения:

    1. можно запустить только из корня РЕПО, иначе произойдет странность...
    2. автоматическое завершение на основе табуляции нарушается при вводе одного из этих псевдонимов
    3. если люди забывают git checkout-symlinks прежде чем делать что-то вроде git add -A, они могли загрязнять РЕПО!

      используя наш "пример РЕПО" из раньше:

      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
      #
      

      Упс...

      по этой причине неплохо включить эти псевдонимы в качестве шагов для выполнения для пользователей Windows до и после создания проекта, а не после проверки или перед нажатием. Но каждая ситуация различна. Эти псевдонимы были достаточно полезны для меня, что истинное решение после проверки не было необходимо.

надеюсь, что помогает!

ссылки:

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

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

2014-11-12 обновления: потому что я лично только когда-либо использовал rm-symlinks и checkout-symlinks псевдонимы выше, мне удалось пропустить довольно неприятную ошибку в add-symlink псевдоним. Ранее,-n не прошел к echo оператор, ответственный за создание файла символической ссылки git, который позже будет добавлен в промежуточную область как часть 'ы. Это означает, что конечная новая строка (0x0D 0x0A на хостах Windows) был добавлен ко всем символическим ссылкам git, созданным с помощью add-symlink. Хотя эти символические ссылки git по-прежнему будут" съемными " на хостах Windows с rm-symlinks просто отлично, если они когда-либо были связаны с публичным РЕПО, а затем клонированы на подлинной системе на основе posix,эти ссылки всегда выходи сломанным с другой стороны. Эта проблема была исправлена, и add-symlink теперь должно работать, как ожидалось.


самая последняя версия git scm (testet 2.11.1) позволяет включить символические ссылки. Но вы должны снова клонировать репозиторий с символическими ссылками git clone -c core.symlinks=true <URL>. Эту команду необходимо выполнить с правами администратора. Также можно создавать символические ссылки на Windows с помощью mklink. Проверьте wiki.

enter image description here


Он должен быть реализован в msysgit, но есть два недостатка:

  • символические ссылки доступны только в Windows Vista и позже (не должно быть проблемой в 2011 году, и все это...), так как более старые версии поддерживают только соединения каталогов.
  • (большой) Microsoft считает символические ссылки угрозой безопасности, и поэтому только администраторы могут создавать их по умолчанию. Вам нужно будет повысить привилегии процесса git или использовать fstool, чтобы изменить это поведение на каждой машине, на которой вы работаете.

Я сделал быстрый поиск и работу активно делается по этому вопросу 224.


Я бы посоветовал вам не использовать символические ссылки в репо. Храните фактическое содержимое внутри РЕПО, а затем размещайте символические ссылки на стороне РЕПО, указывающие на содержимое.

Итак, скажем, вы используете репо, чтобы сравнить хостинг вашего сайта на *nix с хостингом на win. Храните контент в своем РЕПО', скажем /httpRepoContent и c:\httpRepoContent С этой папкой, которая синхронизируется через GIT, SVN и т. д.

затем замените папку содержимого вашего веб-сервера (/var/www и c:\program files\web server\www {имена не так важны, изменить, если необходимо}) с символической ссылкой на контент в вашем РЕПО. Веб-серверы будут видеть содержимое как на самом деле в "правильном" месте, но вы можете использовать свой исходный элемент управления.

однако, если вам нужно использовать символические ссылки в репо, вам нужно будет изучить что-то вроде скриптов до/после фиксации. Я знаю, что вы можете использовать их для выполнения таких действий, как, например, разбор файлов кода через форматер, поэтому должно быть возможно преобразование символических ссылок между платформами.

если кто-то знает хорошее место, чтобы узнать, как сделать эти сценарии для общих элементов управления версиями, SVN GIT MG, то, пожалуйста, добавьте комментарий.


для тех, кто использует CygWin на Vista, Win7 или выше, родной git команда может создавать" правильные " символические ссылки, которые распознаются приложениями Windows, такими как Android Studio. Вам просто нужно установить CYGWIN переменной окружения для включения winsymlinks:native или winsymlinks:nativestrict такие как:

export CYGWIN="$CYGWIN winsymlinks:native"

недостатком этого (и значительного) является то, что оболочка CygWin должна быть "запущена как администратор", чтобы она имела разрешения ОС, необходимые для создать симлинки. Однако после их создания для использовать них. Пока они не изменены в репозитории другим разработчиком,git после этого работает нормально с обычными разрешениями пользователя.

лично я использую этот только для символических ссылок, которые перемещаются приложениями Windows (т. е. не CygWin) из-за этой дополнительной трудности.

для получения дополнительной информации об этой опции см. Этот вопрос SO: как сделать символическую ссылку с cygwin в Windows 7


вот пакетный скрипт для преобразования символических ссылок в репозиторий, только для файлов, основанный на ответе Джоша ли. Скрипт с дополнительной проверкой прав администратора находится по адресу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

короткий ответ: теперь они поддерживаются хорошо, если вы можете включить режим разработчика.

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

теперь в Windows 10 Creators Update пользователь (с правами администратора) может сначала включите Режим разработчика, а затем любой пользователь на компьютере может запустить команда mklink без подъема консоли командной строки.

что вызвало это изменение? Наличие и использование из симлинки большая сделка с современными разработчиками:

многие популярные инструменты разработки, такие как Git и менеджеры пакетов, такие как npm распознавание и сохранение символических ссылок при создании репозиториев или пакетов, соответственно. Когда эти репозитории или пакеты затем восстанавливаются в другом месте символические ссылки также восстанавливаются, обеспечивая дисковое пространство (и время пользователя) не тратится впустую.

легко пропустить со всеми другими объявлениями "обновления Создателя", но если вы включите Режим разработчика, вы можете создавать символические ссылки без повышенных привилегий. Возможно, вам придется переустановить и убедиться, что поддержка включена, поскольку это не по умолчанию.

Symbolic Links aren't enabled by default


Я искал простое решение для работы с символическими ссылками unix в windows. Большое спасибо за вышеуказанные псевдонимы Git. Существует одна небольшая оптимизация, которую можно сделать с символическими ссылками rm, чтобы она не удаляла файлы в папке назначения в случае, если псевдоним запускается второй раз случайно. Обратите внимание на новое условие if в цикле, чтобы убедиться, что файл еще не является ссылкой на каталог до запуска логики.

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 

Я использую ссылки sym все время между моим корнем документа и каталогом git repo. Мне нравится держать их порознь. В windows я использую опцию mklink /j. Соединение, похоже, позволяет git вести себя нормально:

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

например:

>mklink /j c:\gitRepos\Posts C:\Bitnami\wamp\apache2\htdocs\Posts


один простой трюк, который мы используем, чтобы просто позвонить git add --all два раза подряд.

например, наши вызовы скриптов фиксации Windows 7:

$ git add --all
$ git add --all

первое добавление рассматривает ссылку как текст и добавляет папки для удаления.

второй add правильно пересекает ссылку и отменяет удаление, восстанавливая файлы.

это менее элегантно, чем некоторые другие предлагаемые решения, но это простое исправление некоторых наших устаревших сред, которые получили симлинки добавил.


так как все изменилось с GIT, так как многие из этих ответов были опубликованы здесь, это правильные инструкции для правильной работы символических ссылок в windows с

августа 2018 года


1. Убедитесь, что git установлен с поддержкой symlink

During the install of git on windows

2. Скажите Bash создать жесткие ссылки вместо символических

редактировать -- (git папка) / etc / bash.bashrc и

ДОБАВИТЬ В НИЖНЕЙ ЧАСТИ -MSYS=winsymlinks:nativestrict

3. Установите git config для использования символических ссылок

git config core.symlinks true

или

git clone -c core.symlinks=true <URL>

примечание: Я попытался добавить это в глобальную конфигурацию git, и на данный момент это не работает для меня, поэтому я рекомендую добавить это в каждое РЕПО...

4. потяните РЕПО

Примечание: Если вы не включили режим разработчика в последней версии Windows 10, вам нужно запустить bash как администратор, чтобы создать символические ссылки

5. Сбросить все символические ссылки (опционально) Если у вас есть существующее РЕПО или вы используете подмодули, вы можете обнаружить, что символические ссылки создаются неправильно, поэтому для обновления всех символических ссылок в репо вы можете запустить эти команды.

find -type l -delete
git reset --hard

Примечание: это сбросит любые изменения с момента последнего фиксации, поэтому убедитесь, что вы совершили первый