Как я могу заставить Git следовать символическим ссылкам?

217

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

PS: я знаю, что это не очень безопасно, но я хочу сделать это только в нескольких конкретных случаях.

Matt
источник
5
Есть ли недостаток в использовании жестких ссылок для чего-то вроде этого?
Этеш Чоудхури
12
В Windows 7 «mklink / d» (символьная ссылка на каталог) не работает с git, но «mklink / j» (juction) работает нормально.
Йоо
1
Если файл автоматически генерируется приложением, которое создает его таким образом, что оно удаляет файл и создает новый, тогда да, это проблема, которую не решают жесткие ссылки на файлы.
Мартин Пецка,
1
@EhteshChoudhury Вы не можете делать жесткие ссылки для каталогов
Гаурав Кансал

Ответы:

45

ПРИМЕЧАНИЕ: этот совет устарел согласно комментарию со времен Git 1.6.1. Git обычно так себя ведет и больше не делает.


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

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

То есть:

  /foo/
  /foo/baz
  /bar/foo --> /foo
  /bar/foo/baz

при выполнении

 git add /bar/foo/baz

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

Кент Фредрик
источник
72
В коммитах 725b06050a083474e240a2436121e0a80bb9f175 и 806d13b1ccdbdde4bbdfb96902791c4b7ed125f6 были внесены изменения, которые не позволили вам добавлять файлы, кроме каталогов с символическими ссылками, так что это не будет работать в версиях git с 1.6.1
Mark Longair
1
$ git add src / main / path / ConvertSymlinkToDir роковая: 'src / main / path / ConvertSymlinkToDir' выходит за рамки символической ссылки
user1767316
2
@ user1767316 прочитать все это и комментарии. Раньше работал, больше не работает. Программное обеспечение изменяется, но ответы о переполнении стека не принимаются. Я уточнил, что это уже не работает. Посмотрите на другой ответ.
Кент Фредрик
да @KentFrederic, но возвращение точного сообщения об ошибке помогло пользователю стека помочь найти решение своей проблемы. Попытался отменить понижение, но заблокировал извините. С одной стороны, ваш ответ правильный с учетом предупреждения, с другой стороны, нужно отдавать приоритет ответу, работающему сейчас, а не в прошлом
user1767316
144

Что я сделал, чтобы добавить файлы внутри символической ссылки в Git (я не использовал символическую ссылку, но):

sudo mount --bind SOURCEDIRECTORY TARGETDIRECTORY

Выполните эту команду в каталоге, управляемом Git. TARGETDIRECTORYдолжен быть создан до того, SOURCEDIRECTORYкак в него вмонтирован.

Он отлично работает на Linux, но не на OS X! Этот трюк помог мне и с Subversion. Я использую его для включения файлов из учетной записи Dropbox, где веб-дизайнер делает свое дело.

user252400
источник
8
Было бы очень хорошим подходом, если бы sudo не требовалось.
MestreLion
13
Чтобы отменить эту привязку, используйте umount [mydir]. (+1 за отличный совет, @ user252400)
JellicleCat
10
Это работает только во время сеанса. Как лучше всего сделать его «вечным»?
Adobe
17
@Adobe: поместите его в / etc / fstab, вот так: / sourcedir / targettdir none bind
Alexander Garden
8
Здесь sshfs может добиться такого трюка, не требуя sudo.
PypeBros
74

Почему бы не создать символические ссылки наоборот? То есть вместо того, чтобы ссылаться из репозитория Git на каталог приложения, просто сделайте ссылку наоборот.

Например, допустим, я устанавливаю приложение, в ~/applicationкотором требуется файл конфигурации config.conf:

  • Я добавляю config.confв свой репозиторий Git, например, at ~/repos/application/config.conf.
  • Затем я создаю символическую ссылку ~/application, запустив ln -s ~/repos/application/config.conf.

Этот подход может не всегда работать, но он до сих пор работал хорошо для меня.

соглядатай
источник
5
Кажется, это единственный путь, и это не так уж и плохо ... я думаю, что у вас довольно элегантный подход. Git отслеживает содержимое, а не файлы. Таким образом, хранение всего контента и символических ссылок оттуда в другие места имеет смысл
MestreLion
12
В моем случае я хотел ссылку с одного git-репо на другой, чтобы я мог редактировать файлы в любом месте и фиксировать их обратно на соответствующие пульты. В Windows 7 соединение («mklink / j») помогло.
Йоо
3
конечно. иногда ответ так прост.
BBW перед Windows
Что если вы хотите использовать как источник, так и пункт назначения? (потому что оба принадлежат разным кодам, которые вы хотите иметь в разных репозиториях)
DrGC
1
Не отвечает на вопрос :( Я хотел, чтобы часть моего репозитория была синхронизирована с моим iCloud. К сожалению, iCloud не следует по символическим ссылкам, поэтому я подумал, что могу заставить git следовать символическим ссылкам и сохранять оригинальные файлы в iCloud. Оказывается, никто не следует символические ссылки: \
Джерри Грин
49

Вместо этого используйте жесткие ссылки. Это отличается от мягкой (символической) ссылки. Все программы, в том числе 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"
fregante
источник
7
Просто примечание: это в основном то, что я искал, но потом я узнал, что в Linux жесткая ссылка, к сожалению, не может пересекать границы файловой системы (что является моим вариантом использования).
sdaau
26
Вы не можете жестко связаться с каталогами, не так ли?
Нанн
1
ln source destinationработает в OS X тоже. Проверено на El Capitan.
Махди Дибайи
7
@Nanne нет, но вы можете сделать: cp -al source destination. `-l 'означает жесткие ссылки на файлы вместо копирования.
Паоло
6
К сожалению, вы не можете жестко связать каталоги или границы файловой системы. Это делает это решение в два раза неработоспособным для меня.
Конрад Рудольф
26

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

Вставьте это .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, возможно, среди прочего.

В этом коде могут быть некоторые ошибки / ошибки, даже если он был несколько протестирован.

Abbafei
источник
4
Замечательно видеть попытку фактически ответить на вопрос для файлов, а не каталогов. Тем не менее, обратите внимание , что выше , будет по- прежнему показывать typechangeв git statusтечение файлов , которые на самом деле символические ссылки , хотя мерзавец теперь все они не являются.
Дэвид Фрейзер
1
Спасибо за это; просто хотел узнать, что это process_links_to_nondir?
sdaau
@sdaau Это имя /, argv[0]которое используется в качестве имени команды для shпроцесса. (Понадобилось немного, чтобы понять это, поскольку я тоже не помню, что это было ☺😃)
Аббафей
3
@Abbafei Можете ли вы изменить скрипт, чтобы он работал в Ubuntu (14.04)? Это показывает find: missing argument to -exec'. Может быть пошаговое выполнение команды, а не сборка и объединение всего в одну строку.
Хуршид Алам
1
@KhurshidAlam Для меня это помогло удалить закомментированные строки между командными строками. Тем не менее, ловушка не работает typechangeдолжным образом (я получаю как @DavidFraser, но связанный файл, похоже, больше не ставится)
Scz
14

Вкл MacOS(у меня Mojave / 10.14, gitверсия 2.7.1), используйте bindfs.

brew install bindfs

cd /path/to/git_controlled_dir

mkdir local_copy_dir

bindfs </full/path/to/source_dir> </full/path/to/local_copy_dir>

На это намекали другие комментарии, но в других ответах это явно не указано. Надеюсь, это сэкономит кому-то время.

ijoseph
источник
Кажется, отлично подходит для команд, которые все работают на Mac OS, я думаю, что жесткие ссылки, изложенные ниже, должны работать для Windows и Linux.
Девин Г. Род
Это было полезно, и я думаю, что лучшее решение для полезной, но отсутствующей возможности в MacOS. Обратите внимание, что я получаю Failed to resolve... No such file or directoryошибки, если я не использовал полные пути с bindfsкомандой.
Электромагнит
Спасибо @electromaggot. Добавлено уточнение, что необходимы полные пути
ijoseph
1
Отлично работает на макосе Каталина!
Джерри Грин
13

Я использовал для добавления файлов за символические ссылки в течение достаточно долгого времени. Раньше это работало просто отлично, без каких-либо специальных мер. Поскольку я обновился до Git 1.6.1, это больше не работает.

Вы можете переключиться на Git 1.6.0, чтобы это работало. Я надеюсь, что в будущей версии Git будет флаг, git-addпозволяющий ему снова следовать символическим ссылкам.

Эрик Шнеттер
источник
12

Я устал от того, что каждое решение здесь устарело или требует root, поэтому я создал решение на основе LD_PRELOAD (только для Linux).

Он подключается к внутренностям Git, переопределяя «это символическая ссылка?» функция, позволяющая обрабатывать символические ссылки как их содержимое. По умолчанию все ссылки на внешние репо являются встроенными; см. ссылку для деталей.

Alcaro
источник
Очень креативное решение LD_PRELOADдля переопределения библиотечных функций!
iBug
Да, но это должно быть уточнено здесь. Вы можете сделать это?
Питер Мортенсен
Не уверен, сколько разработок поможет; если я не скопирую весь исходный код, этот ответ всегда будет опираться на эту ссылку, где также можно найти файл readme. Но да, я думаю, я мог бы воспроизвести важные части readme.
Алькаро
Это не компилируется в OS X (Mojave 10.14.2). Получите четыре ошибки с жалобами на «strchrnul» (вы имели в виду «strchr»?) И одну на «__xstat64» (вы имели в виду «__lxstat64»?). Наконец, я получаю сообщение об ошибке «доступ члена к неполному типу dirent64». Бывает независимо от того, использую ли я «make», «make OPT = 1» или «sh install.sh».
Эрик Веланд
@ErikVeland Я немного попробовал, но, похоже, OSX не поддерживает ни LD_PRELOAD, ни что-либо подобное. Различные документы предлагают разные вещи, но им всего несколько лет, и Apple любит осуждающие вещи; Я не мог заставить их работать. Сожалею.
Алькаро
6

В 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
VonC
источник
4

Хммм, mount --bindпохоже, не работает на Дарвина.

У кого-нибудь есть трюк, который делает?

[Отредактированный]

Хорошо, я нашел ответ на Mac OS X, чтобы сделать жесткую ссылку. За исключением того, что этот API не предоставляется через ln, поэтому вы должны использовать свою собственную крошечную программу для этого. Вот ссылка на эту программу:

Создание каталогов жестких ссылок в Mac OS X

Наслаждайтесь!

J Chris A
источник
1
Если каталог назначения этой жесткой ссылки является подкаталогом другого git-репо, это будет хаос. Выполнение операций git в hardlink будет применяться к этому другому git-репо. Просто дважды проверьте, что вы делаете.
Yegle
4
Это можно сделать с помощью code.google.com/p/bindfs, который можно установить с помощью порта.
Кит Сунд
0

Я использую Git 1.5.4.3, и он следует переданной символической ссылке, если он имеет косую черту. Например

# Adds the symlink itself
$ git add symlink

# Follows symlink and adds the denoted directory's contents
$ git add symlink/
Питер Мортенсен
источник
5
по крайней мере, на OSX это приводит кfatal: 'src/' is beyond a symbolic link
Дэн Розенстарк
2
Как объяснил @Mark Longair, это работало только до git 1.6.1
MestreLion
это была моя проблема, спасибо!
Майк Q
0

Преобразование из символических ссылок может быть полезным. Ссылка в папке Git вместо символической ссылки скриптом .

Yurij73
источник
Хотите добавить больше деталей к вашему ответу?
Девин Г. Род