Как я могу заставить 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.

Из часто задаваемых вопросов APFS на developer.apple.com

Следуйте 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 вместо символической ссылки скриптом.

Другие вопросы по тегам