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

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

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

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


person Alex    schedule 05.06.2009    source источник
comment
.gitignore видит символическую ссылку как файл, а не как папку.   -  person 0xcaff    schedule 03.02.2014
comment
Что ж, очевидно, в вопросе есть нечто большее, чем следует из этого ответа. Например, мне интересно следующее: если я создам символьную ссылку в моем репозитории на какой-то большой файл в этом репозитории, отправлю изменения, а затем перенесу эти изменения на другую машину, что произойдет? Будет ли большой файл сохранен как большой файл в обоих местах или будет сохранена символьная ссылка, так что на новом компьютере файл ссылки будет указывать на исходный большой файл?   -  person jvriesem    schedule 13.06.2014
comment
Это старая ветка, но этот комментарий все еще может быть полезен. В ответ на jviesem программная ссылка - это в основном файл с именем другого файла. Таким образом, как только вы перетащите его на другую машину, ссылка будет загружена, и у нее будет имя большого файла в исходной файловой системе. Если на новой машине имя недействительно, тогда ссылка будет иметь недопустимое имя. Большой файл не будет загружен на новую машину.   -  person lasaro    schedule 19.11.2015
comment
@lasaro, способ избежать битых ссылок в репозитории git - всегда использовать относительные пути при создании символических ссылок, используя ../.. по мере необходимости.   -  person Wildcard    schedule 23.01.2016
comment
git add -f filename добавить в git   -  person HoKy22    schedule 02.04.2017
comment
Обратите внимание, что в большинстве версий Windows вам нужны повышенные разрешения для создания символической ссылки. Если вы работаете в Windows и git pull создает файл вместо символической ссылки, попробуйте запустить клиент Git от имени администратора.   -  person axmrnv    schedule 30.05.2017
comment
Информация о том, что git делает в Windows; stackoverflow.com/questions/11662868/   -  person brillout    schedule 20.10.2017


Ответы (4)


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

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

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

person CB Bailey    schedule 05.06.2009
comment
КСТАТИ. Если вы работаете в файловой системе, такой как FAT, которая не поддерживает символические ссылки, и ваш репозиторий использует их, вы можете установить для переменной конфигурации core.symlinks значение false, и символические ссылки будут извлечены как небольшие текстовые файлы, содержащие текст ссылки. - person Jakub Narębski; 05.06.2009
comment
@ JakubNarębski Я видел это раньше. В нашем репо был текстовый файл с одной строкой - путем к библиотеке, которую мы используем. Не мог понять, с какой целью. Теперь я знаю, что случилось. - person Matt K; 10.04.2014
comment
Я не решаюсь комментировать ответ, получивший большое количество голосов, но я думаю, что формулировка, как и для обычного файла, может вводить в заблуждение новичков. Он похож на обычный файл, только его содержимое находится в виде большого двоичного объекта. Критическое отличие состоит в том, что для обычного файла большой двоичный объект является содержимым файла, но для символической ссылки большой двоичный объект имеет путь к файлу, на который он ссылается. - person Matthew Hannigan; 25.10.2014
comment
@ JakubNarębski Относительно небольших текстовых файлов ... Можно было бы надеяться, что они маленькие и текстовые, но, конечно, blob - это blob, и потенциально может быть огромным и двоичным. См. stackoverflow.com/questions/18411200/, если файл ошибочно указан как символическая ссылка. - person Matthew Hannigan; 25.10.2014
comment
Обязательно проверьте свои глобальные настройки на наличие символических ссылок и локальные настройки для символических ссылок. Если настройки были скопированы из TortiseGit или Windows, вы могли symlinks = false возиться с ними. - person phyatt; 12.12.2017
comment
А как насчет того, чтобы пойти в другом направлении? Т.е. файлы в репо связаны откуда-то еще? Это как-то негативно сказывается на репо? - person posfan12; 06.09.2020

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

Сначала сделайте символическую ссылку:

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

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

$ git ls-files -s ./symlink
[nothing]

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

$ git add ./symlink

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

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

Хеш - это ссылка на упакованный объект, созданный в хранилище объектов. Вы можете изучить этот объект, если посмотрите .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15c в корне вашего репозитория. Это файл, который Git хранит в репозитории, который вы можете позже получить. Если вы изучите этот файл, вы увидите, что он очень маленький. Он не сохраняет содержимое связанного файла. Чтобы убедиться в этом, распечатайте содержимое упакованного объекта репозитория с помощью git cat-file:

$ git cat-file -p 1596f9db1b9610f238b78dd168ae33faa2dec15c
/path/referenced/by/symlink

(Примечание 120000 - это режим, указанный в ls-files выводе. Это будет что-то вроде 100644 для обычного файла.)

Но что Git делает с этим объектом, когда вы извлекаете его из репозитория в свою файловую систему? Это зависит от конфигурации core.symlinks. Из man git-config:

core.symlinks

Если false, символические ссылки извлекаются как небольшие простые файлы, содержащие текст ссылки.

Итак, с символической ссылкой в ​​репозитории при оформлении заказа вы получаете либо текстовый файл со ссылкой на полный путь к файловой системе, либо правильную символическую ссылку, в зависимости от значения core.symlinks config.

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

person Dmitry Minkovsky    schedule 13.09.2013
comment
Гарантируется ли, что путь ссылки, который хранится на удаленном компьютере, будет относительным, если он указывает на путь внутри репо? А как насчет путей выхода за пределы репо? Абсолютно или относительно корня проекта? Это зависит от того, как сделана ссылка? - person geekley; 14.11.2020
comment
Да, я думаю, это зависит от того, как вы создаете символическую ссылку. Если вы создадите его, и к месту назначения будет добавлен префикс /, тогда он будет абсолютным и может указывать за пределы вашего репо. В противном случае он будет относительным. Если он относительный и указывает на ваше репо, он должен быть переносимым, по крайней мере, между Unix-подобными системами. - person Dmitry Minkovsky; 14.11.2020
comment
@geekley Не уверен, как я случайно уронил это во время редактирования, но вы можете увидеть содержимое объекта хранилища git с помощью git cat-file -p, поэтому, если хэш вашей символической ссылки c6e5580589892eb40407c74a825afaa6c9315787, вы можете сделать git cat-file -p c6e5580589892eb40407c74a825afaa6c9315787 и просмотреть содержимое этого файла пакета, который является просто символическая ссылка - person Dmitry Minkovsky; 14.11.2020

Примечание редактора: это сообщение может содержать устаревшую информацию. См. Комментарии и этот вопрос относительно изменений в Git с версии 1.6. .1.

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

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

Пример

До

 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
person Shekhar    schedule 02.10.2009
comment
Стоит отметить, что эти предупреждения о каталогах с символическими ссылками не относятся к версионным символическим ссылкам. Основным пограничным случаем, о котором идет речь, было то, что люди символически связывали часть или все рабочее дерево на другой путь (скажем, на другой раздел с большим дисковым пространством) и ожидали, что git проверит код через существующую символическую ссылку. То есть, если у вас есть проект, который содержит версионные символьные ссылки на файлы или каталоги, обычное поведение символьной ссылки как blob будет сохранять символьные ссылки, правильно изменять версии этих символических ссылок и в остальном работать должным образом. - person John Whitley; 22.12.2009
comment
Вышеупомянутое поведение проверено с помощью git 1.6.5.6; но я сильно подозреваю, что версионное поведение было правильным в git в течение некоторого времени. - person John Whitley; 22.12.2009
comment
Я пытаюсь решить эту проблему, которая у меня тоже возникла. Похоже на ошибку с git-pull, переводящей результат по какой-то причине. - person Kevin; 05.04.2011
comment
Присутствует ли такое поведение во всех версиях git или исправлено? - person jbotnik; 10.06.2011
comment
Похоже, что теперь это поведение исправлено, см. stackoverflow.com/a/1943656/1334781 - person Ron Wertlen; 25.09.2014
comment
Шекар: Поместите ли вы в свой ответ правку, чтобы отразить изменения в git за последние годы? - person einpoklum; 22.06.2017
comment
@RonWertlen Это ссылка на тот же вопрос. - person alx; 05.08.2020

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

См. фиксацию fab78a0, commit 462b4e8 (18 марта 2021 г.) от (matheustavares).
(Объединено Junio ​​C Hamano - gitster - в commit 9210c68, 30 марта 2021 г.)

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

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

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

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

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

person VonC    schedule 31.03.2021