Как я могу заставить Git следовать символическим ссылкам?
Лучше всего будет сценарий оболочки, который заменяет символические ссылки на копии, или есть другой способ сказать Git следовать символическим ссылкам?
PS: я знаю, что это не очень безопасно, но я хочу сделать это только в нескольких конкретных случаях.
14 ответов
ПРИМЕЧАНИЕ: этот совет устарел согласно комментарию со времен Git 1.6.1. Git обычно так себя ведет и больше не делает.
Git по умолчанию пытается хранить символические ссылки вместо того, чтобы следовать за ними (для компактности, и это обычно то, что люди хотят).
Однако мне случайно удалось заставить его добавлять файлы за пределы символьной ссылки, когда символическая ссылка является каталогом.
То есть:
/foo/
/foo/baz
/bar/foo --> /foo
/bar/foo/baz
при выполнении
git add /bar/foo/baz
оказалось, что работает, когда я попробовал. Это поведение, однако, было нежелательным для меня в то время, поэтому я не могу дать вам информацию, кроме этого.
Что я сделал, чтобы добавить файлы внутри символической ссылки в Git (я не использовал символическую ссылку, но):
sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY
Выполните эту команду в каталоге, управляемом Git. TARGETDIRECTORY
должен быть создан до SOURCEDIRECTORY
вмонтирован в него.
Он отлично работает на Linux, но не на OS X! Этот трюк помог мне и с Subversion. Я использую его для включения файлов из учетной записи Dropbox, где веб-дизайнер делает свое дело.
Почему бы не создать символические ссылки наоборот? То есть вместо того, чтобы ссылаться из репозитория Git на каталог приложения, просто сделайте ссылку наоборот.
Например, допустим, я настраиваю приложение, установленное в ~/application
который нуждается в файле конфигурации config.conf
:
- я добавить
config.conf
в мой репозиторий Git, например, в~/repos/application/config.conf
, - Затем я создаю символическую ссылку из
~/application
запустивln -s ~/repos/application/config.conf
,
Этот подход может не всегда работать, но он до сих пор работал хорошо для меня.
Вместо этого используйте жесткие ссылки. Это отличается от мягкой (символической) ссылки. Все программы, в том числе git
будет рассматривать файл как обычный файл. Обратите внимание, что содержимое может быть изменено путем изменения источника или назначения.
В macOS (до 10.13 High Sierra)
Если у вас уже установлены git и Xcode, установите hardlink. Это микроскопический инструмент для создания жестких ссылок.
Чтобы создать жесткую ссылку, просто:
hln source destination
Обновление macOS High Sierra
Поддерживает ли Apple File System жесткие ссылки на каталоги?
Жесткие ссылки на каталоги не поддерживаются файловой системой Apple. Все жесткие ссылки на каталоги преобразуются в символические ссылки или псевдонимы при преобразовании из форматов томов HFS+ в APFS в macOS.
Следуйте https://github.com/selkhateeb/hardlink/issues/31 для будущих альтернатив.
В Linux и других разновидностях Unix
ln
Команда может создавать жесткие ссылки:
ln source destination
В Windows (Vista, 7, 8, …)
Кто-то предложил использовать mklink для создания соединения в Windows, но я не пробовал:
mklink /j "source" "destination"
Это хук перед фиксацией, который заменяет двоичные объекты символьных ссылок в индексе содержимым этих символических ссылок.
Поместите это в .git/hooks/pre-commit
и сделайте его исполняемым:
#!/bin/sh
# (replace "find ." with "find ./<path>" below, to work with only specific paths)
# (these lines are really all one line, on multiple lines for clarity)
# ...find symlinks which do not dereference to directories...
find . -type l -exec test '!' -d {} ';' -print -exec sh -c \
# ...remove the symlink blob, and add the content diff, to the index/cache
'git rm --cached "$1"; diff -au /dev/null "$1" | git apply --cached -p1 -' \
# ...and call out to "sh".
"process_links_to_nondir" {} ';'
# the end
Заметки
Мы максимально используем POSIX-совместимую функциональность; тем не мение, diff -a
не совместим с POSIX, возможно, среди прочего.
В этом коде могут быть некоторые ошибки / ошибки, даже если он был несколько протестирован.
На MacOS
использовать bindfs
,
brew install bindfs
cd /path/to/git_controlled_dir
mkdir local_copy_dir
bindfs <source_dir> local_copy_dir
На это намекали другие комментарии, но в других ответах это явно не указано. Надеюсь, это сэкономит кому-то время.
Я устал от того, что каждое решение здесь или устарело, или требует root, поэтому я создал решение на основе LD_PRELOAD.
Он подключается к внутренностям Git, переопределяя "это символическая ссылка?" функция, позволяющая обрабатывать символические ссылки как их содержимое. По умолчанию все ссылки на внешние репо являются встроенными; см. ссылку для деталей.
Я использовал для добавления файлов за символические ссылки в течение достаточно долгого времени. Раньше это работало просто отлично, без каких-либо специальных мер. Поскольку я обновился до Git 1.6.1, это больше не работает.
Вы можете переключиться на Git 1.6.0, чтобы сделать это. Я надеюсь, что будущая версия Git будет иметь флаг git-add
позволяя ему снова следовать символическим ссылкам.
В Git 2.3.2+ (первый квартал 2015 года) есть еще один случай, когда Git больше не будет следовать символической ссылке: см. Commit e0d201b от Junio C Hamano ( gitster
) (главный сопровождающий Git)
apply
: не трогать файл за символической ссылкой
Поскольку Git отслеживает символические ссылки как символические ссылки, путь, который имеет символическую ссылку в своей ведущей части (например,
path/to/dir/file
, гдеpath/to/dir
является символической ссылкой куда-то еще, будь то внутри или вне рабочего дерева), никогда не может появиться в патче, который корректно применяется, если только этот же патч сначала не удаляет символическую ссылку, чтобы разрешить создание каталога там.Обнаружить и отклонить такой патч.
Точно так же, когда вход создает символическую ссылку
path/to/dir
а затем создает файлpath/to/dir/file
нам нужно пометить его как ошибку без фактического созданияpath/to/dir
символическая ссылка в файловой системе.Вместо этого, для любого патча во входных данных, который оставляет путь (т.е. не удаляет) в результате, мы проверяем все начальные пути по результирующему дереву, которое патч будет создавать, проверяя все патчи на входе, а затем цель патча. приложение (либо индекс, либо рабочее дерево).
Таким образом, мы:
- поймать шалость или ошибку, чтобы добавить символическую ссылку
path/to/dir
и файлpath/to/dir/file
в то же время,- допуская действительный патч, который удаляет символический
link path/to/dir
а затем добавляет файлpath/to/dir/file
,
Это означает, что в этом случае сообщение об ошибке не будет общим, как "%s: patch does not apply"
, но более конкретный:
affected file '%s' is beyond a symbolic link
Хммм, mount --bind
похоже, не работает на Дарвина.
У кого-нибудь есть трюк, который делает?
[Редактировать]
Хорошо, я нашел ответ на Mac OS X, чтобы сделать жесткую ссылку. За исключением того, что этот API не выставляется через ln
так что вы должны использовать свою собственную крошечную программу для этого. Вот ссылка на эту программу:
Создание каталогов жестких ссылок в Mac OS X
Наслаждайтесь!
Альтернативная реализация того, что предлагает @user252400, заключается в использованииbwrap
, небольшая песочница setuid, которую можно найти во всех основных дистрибутивах - часто устанавливается по умолчанию. bwrap
позволяет связывать каталоги монтирования без sudo
и автоматически отвязывает их при выходе из git или вашей оболочки.
Предполагая, что ваш процесс разработки не слишком сумасшедший (см. Ниже), запустите bash в частном пространстве имен и привяжите внешний каталог к каталогу git:
bwrap --ro-bind / / \
--bind {EXTERNAL-DIR} {MOUNTPOINT-IN-GIT-DIR} \
--dev /dev \
bash
Тогда делай все, что обычно хочешь git add
, git commit
, и так далее. Когда вы закончите, просто выйдите из bash. Чисто и просто.
Предостережения: чтобы предотвратить побег из песочницы, bwrap
не разрешено выполнять другие двоичные файлы setuid. Увидетьman bwrap
Больше подробностей.
Я использую Git 1.5.4.3, и он следует переданной символической ссылке, если он имеет косую черту. Например
# Adds the symlink itself
$ git add symlink
# Follows symlink and adds the denoted directory's contents
$ git add symlink/
1. Вам следует использовать жесткие ссылки, поскольку изменения, внесенные в жесткие ссылки, производятся git.
2. Синтаксис для создания жесткой ссылки:
ln file1 file2
.
3. Здесь file1 - это расположение файла, жесткую ссылку на который вы хотите создать, а file2 - это расположение жесткой ссылки.
4. Надеюсь, это поможет.
Преобразование из символических ссылок может быть полезным. Ссылка в папке Git вместо символической ссылки скриптом.