Git Symlinks в Windows

182

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

Решение (обновлено), которое у меня есть:

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

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

Вопросы:

  • Что, если таковые имеются, то вы видите этот подход?
  • Является ли этот пост-checkout script даже выполнимым? то есть я могу рекурсивно узнать фиктивные "символические" файлы git создает?
  • Кто-нибудь уже работал над такими script?
  • 3
    Хотя Git поддерживает символические ссылки, я настоятельно рекомендую не сохранять их как ссылки в вашем хранилище, особенно если вы также работаете с этим кодом в Windows.
  • 2
    @ Грег Хьюгилл - я полностью с тобой согласен. К сожалению, природа нашей кодовой базы требует символических ссылок ... поэтому удаление их не вариант для нас.
Показать ещё 7 комментариев
Теги:
symlink

12 ответов

88
Лучший ответ

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

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

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

  • 2
    Мне пришлось заменить awk на gawk для msysgit, но в остальном он работал отлично. Спасибо!
  • 5
    привет кен. Не могли бы вы поделиться своим сценарием, который проверяет текстовые файлы символических ссылок и заменяет их символическими ссылками на окнах с помощью mklink. в то время как это на самом деле работает для нас, --assume-неизмененная часть не работает. при переключении на другую ветку git говорит, что файлы символических ссылок изменены, и их нужно сначала зафиксировать, а git status говорит, что никаких изменений нет.
Показать ещё 8 комментариев
162

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

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

Решение:

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

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

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

    ОБНОВЛЕНО 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'\' root dir.
    * Command must be run from the repository'\' 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 -- "$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'
    

    Применение:

    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 (в случае каталогов). Преимущество использования ссылок hardlinks + над "истинными" символическими ссылками NTFS заключается в том, что для того, чтобы они могли быть созданы, не требуются повышенные права UAC. Наконец, на собственном отдыхе вы можете отключить -A s-модифицированные (или не) "удаленные" символические ссылки с помощью git update-index.

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

    git rm-symlinks
    

    Это удаляет ВСЕ ссылки git symlinks в текущем репозитории, заменяя их жесткими ссылками + переходы по мере необходимости и автоматически помещая изменения, которые следует игнорировать по 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 до того, как -A nd -A создаст проект, а не после проверки или до нажатия. Но каждая ситуация другая. Эти псевдонимы были достаточно полезны для меня, что настоящая post- проверка не требовалась.

Надеюсь, это поможет!

Рекомендации:

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

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

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

  • 0
    не могли бы вы взглянуть на это здесь? stackoverflow.com/questions/21403772/...
  • 8
    Феноменальный ответ, огромное спасибо за это!
Показать ещё 9 комментариев
38

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

Изображение 7324

  • 1
    Это не сработало для меня. Я переустановил git для Windows, не забудьте проверить флажок символической ссылки и снова клонировать мой проект. Мой файл tslint.json ссылающийся на файл в родительском каталоге, все еще содержит ../tslint.json . Жаль, потому что это действительно выглядело как самое простое из всех предложенных решений.
  • 7
    @JanAagaard Вы должны клонировать его так: git clone -c core.symlinks=true <URL> А в Windows вы должны запустить его с правами администратора.
Показать ещё 6 комментариев
14

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

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

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

  • 2
    Обновление: по вышеуказанным причинам проблема была закрыта как wontfix. Обсуждение показывает, что исправление может быть принято с некоторой дополнительной работой над патчем (скажем, с использованием символических ссылок, только если они работают).
  • 2
    A.) в настоящее время msysgit вообще не поддерживает символические ссылки - так почему бы не сделать так, чтобы он обнаруживал: «о, у вас перспективы с NTFS, позвольте мне использовать символические ссылки» или «о, вы работаете в ОС, которая поддерживает соединения с NTFS, позвольте мне использовать эти "или" о, вы на Windows 98 / FAT32, позвольте мне вернуться к тому, что у вас нет этой функции и вместо этого выдается предупреждение! " а затем Б.) Почти все разработчики Microsoft. инструменты не работают должным образом (по крайней мере, не для всех их функций), если вы не запускаете их как администратор - все в ИТ знают, что разработчики должны быть администраторами в своих собственных блоках.
Показать ещё 3 комментария
9

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

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

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

Однако, если вам нужно использовать символические ссылки в репо ', вам нужно будет изучить нечто вроде скриптов pre/post commit. Я знаю, что вы можете использовать их, чтобы делать что-то, например, файлы кода синтаксического анализа через форматирование, например, чтобы было возможно преобразовать символические ссылки между платформами.

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

  • 0
    В конце концов, я выбрал этот подход, чтобы создать папку с символическими ссылками и создать символические ссылки на место, где был оригинальный файл. Другой подход не сработал даже после того, как я изменил настройки .git / config core.symlinks = true. В хранилище был сохранен только файл символической ссылки, а не данные. Также были проблемы с отметками времени папок по символической ссылке, поэтому git bash никогда не видел, когда в папке изменялся файл.
  • 0
    Я думаю, что @Eggs вы видели в том, что ссылка была в репозитории, и поэтому git сохранил ее, что проще. Проблема, однако, в том, что цель находилась вне репо, а git не переходит по ссылке на данные цели. В Linux у вас есть тип ссылки, которая будет работать для этого, в основном, у вас есть два пути к одним и тем же данным, хранящимся на диске; Я чувствую, что новые окна могут сделать это сейчас. В любом случае, я все еще не думаю, что это будет делать то, что хотят люди.
Показать ещё 1 комментарий
7

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

export CYGWIN="$CYGWIN winsymlinks:native"

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

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

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

4

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

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

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

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

Что привело к этому изменению? Доступность и использование символических ссылок - это большое дело для современных разработчиков:

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

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

Изображение 7325

2

Я искал легкое решение для решения символических ссылок unix на окнах. Большое спасибо за вышеупомянутые псевдонимы Git. Существует одна небольшая оптимизация, которая может быть выполнена с помощью rm-symlinks, чтобы она не удаляла файлы в целевой папке в случае, если псевдоним запускается во второй раз случайно. Пожалуйста, соблюдайте новое условие 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 
1

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

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

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

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

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

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

1

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

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

например:

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

  • 1
    Будьте очень осторожны с Windows Explorer и соединениями; он не дифференцирует соединения от базового местоположения, и удаление будет возвращаться в цель и удалять его содержимое, тогда как удаление символической ссылки просто удалит символическую ссылку. Просто ловушка для неосторожных.
  • 3
    На самом деле, только что проверил это на последней из Windows7, и он больше не делает, так что обработка переходов была улучшена когда-то в последние несколько лет.
0

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

АВГУСТ 2018


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

Изображение 7326

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

EDIT - (папка 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. Сбросьте все Symlinks (необязательно). Если у вас есть существующее репо или вы используете подмодули, вы можете обнаружить, что символические ссылки создаются неправильно, поэтому для обновления всех символических ссылок в репо вы можете запускать эти команды.

find -type l -delete
git reset --hard

ПРИМЕЧАНИЕ. Это приведет к сбросу любых изменений с момента последнего фиксации, поэтому убедитесь, что вы совершили первый

Ещё вопросы

Сообщество Overcoder
Наверх
Меню