Как Git обрабатывает символические ссылки?

Если у меня есть файл или каталог, который является символической ссылкой, и я помещаю его в репозиторий Git, что с ним происходит?

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

Что он делает, когда я удаляю файл, на который ссылается? Это просто фиксирует висячую ссылку?

4 ответа

Решение

Git просто хранит содержимое ссылки (т. Е. Путь к объекту файловой системы, на которую он ссылается) в "blob", как это делается для обычного файла. Затем он сохраняет имя, режим и тип (включая тот факт, что это символическая ссылка) в объекте дерева, который представляет его содержащий каталог.

Когда вы извлекаете дерево, содержащее ссылку, он восстанавливает объект как символическую ссылку независимо от того, существует целевой объект файловой системы или нет.

Если вы удалите файл, на который ссылается символическая ссылка, он никак не повлияет на управляемую Git символическую ссылку. У вас будет свисающая ссылка. Пользователь может удалить или изменить ссылку, чтобы указать на что-то действительное, если это необходимо.

TL;DR: данные, на которые ссылается символическая ссылка, не сохраняются в хранилище.


Вы можете узнать, что Git делает с файлом, увидев, что он делает, когда вы добавляете его в индекс. Индекс похож на предварительную фиксацию. С указанным индексом вы можете использовать git checkout вернуть все, что было в индексе, обратно в рабочий каталог. Итак, что делает Git, когда вы добавляете в индекс символическую ссылку?

Чтобы выяснить это, сначала сделайте символическую ссылку:

$ ln -s /Path/referenced/by/symlink symlink

Git еще не знает об этом файле. git ls-files позволяет проверить ваш индекс (-s печать stat -подобный вывод):

$ git ls-files -s ./symlink
$

Теперь добавьте содержимое символической ссылки в хранилище объектов Git, добавив его в индекс. Когда вы добавляете файл в индекс, Git сохраняет его содержимое в хранилище объектов Git.

$ git add ./symlink

Итак, что было добавлено?

$ git ls-files -s ./symlink
120000 1596f9db1b9610f238b78dd168ae33faa2dec15c 0       symlink
$

Хеш является ссылкой на упакованный объект, который был создан в хранилище объектов Git. Вы можете изучить этот объект, если вы посмотрите в .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c,

120000 это файловый режим. Это было бы что-то вроде 100644 для обычного файла и является специальным режимом для ссылок. От man git-config:

core.symlinks

Если ложь, символические ссылки извлекаются в виде небольших простых файлов, которые содержат текст ссылки. git-update-index(1) и git-add(1) не изменят тип записи на обычный файл.

использование git cat-file -p красиво распечатать содержимое:

$ git cat-file -p 1596f9db1
/Path/referenced/by/symlink

Вот что Git делает с символической ссылкой: когда вы git checkout по символической ссылке вы либо получаете текстовый файл со ссылкой на полный путь к файловой системе, либо символическую ссылку, в зависимости от конфигурации. Данные, на которые ссылается символическая ссылка, не хранятся в хранилище.

Примечание "Редактора": эта публикация может содержать устаревшую информацию. Пожалуйста, смотрите комментарии и этот вопрос относительно изменений в Git начиная с 1.6.1.

Символьные каталоги:

Важно отметить, что происходит, когда существует каталог, который является мягкой ссылкой. Любое Git pull с обновлением удаляет ссылку и делает ее нормальной директорией. Это то, чему я научился трудным путем. Некоторые идеи здесь и здесь.

пример

До

 ls -l
 lrwxrwxrwx 1 admin adm   29 Sep 30 15:28 src/somedir -> /mnt/somedir

git add/commit/push

It remains the same

После git pull И некоторые обновления найдены

 drwxrwsr-x 2 admin adm 4096 Oct  2 05:54 src/somedir

Особый случай: когда "git checkout" (man) удаляет путь, которого нет в коммите, который он проверяет, он был недостаточно осторожен, чтобы не следовать символическим ссылкам, что было исправлено с помощью Git 2.32 (2 квартал 2021 года).

См. , commit 462b4e8 (18 марта 2021 г.) Матеус Таварес ( matheustavares).
(Слияние Junio ​​C Hamano - gitster- в коммите 9210c68, 30 марта 2021 г.)

Commit fab78a0checkout: не следуйте символическим ссылкам при удалении записей

Подписано: Матеус Таварес

На 1d718a5 («не перезаписывать неотслеживаемые символические ссылки», 20.02.2011, Git v1.7.5-rc0 - слияние ), symlink.c:check_leading_path() начал возвращать разные коды для FL_ENOENT а также FL_SYMLINK.
Но один из его вызывающих, не был настроен на это изменение, поэтому он начал следовать символическим ссылкам на ведущем пути записей, подлежащих удалению.
Исправьте это и добавьте регрессионный тест.

И поскольку мы больше не пытаемся разъединить такие пути, мы также не получаем предупреждение от remove_or_warn().

В случае обычных файлов и символических ссылок сомнительно, было ли предупреждение вообще полезно: unlink_entry()удаляет отслеживаемые пути, которые больше не должны присутствовать в состоянии, которое мы проверяем.
Если ведущий каталог пути был заменен другим файлом, это означает, что базовое имя уже не существует, поэтому нет необходимости в предупреждении.
Конечно, мы оставляем обычный файл или символическую ссылку в пути к dirname, но этот файл сейчас либо не отслеживается (так что опять же, не нужно предупреждать), либо он будет заменен отслеживаемым файлом на следующем этапе этой проверки.

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