Як Git обробляє символічні посилання?


1607

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

Я б припустив, що він залишає його як символічне посилання, поки файл не буде видалений, а потім, якщо ви повернете файл зі старої версії, він просто створить звичайний файл.

Що це робиться, коли я видаляю файл, на який посилається? Чи просто він здійснює звисаючу ланку?


19
.gitignoreбачить символьне посилання як файл, а не папку.
0xcaff

6
Ну, очевидно, що питання є більше, ніж це відповідає. Наприклад, мені цікаво наступне: якщо я створити симпосилання в моєму сховищі до якогось великого файлу в цьому сховищі, натисніть на зміни, а потім перетягніть ці зміни на іншу машину, що буде? Чи збережеться великий файл у великому файлі в обох місцях, чи збережеться посилання sym таким чином, що на новій машині файл посилання вказує на вихідний великий файл?
jvriesem

7
Це стара тема, але цей коментар може бути корисним. У відповідь на jviesem, м'яке посилання - це в основному файл з іменем іншого файлу. Отже, як тільки ви перетянете його на іншу машину, посилання буде завантажено, і воно матиме назву великого файлу в оригінальній файловій системі. Якщо на новій машині ім’я недійсне, тоді посилання матиме недійсне ім’я. Великий файл не завантажуватиметься на нову машину.
лазаро

6
@lasaro, спосіб уникнути порушених посилань у git repo - це завжди використовувати відносні шляхи під час створення символьних посилань, використовуючи ../..за потребою.
Wildcard

8
Зауважте, що для більшості версій Windows вам потрібні підвищені дозволи для створення символьної посилання. Якщо ви працюєте в Windows і git pullстворюєте файл замість символьного посилання, спробуйте запустити клієнта Git як адміністратора.
axmrnv

Відповіді:


1348

Git просто зберігає вміст посилання (тобто шлях об’єкта файлової системи, на який він посилається) у "крапку", як і для звичайного файлу. Потім він зберігає ім'я, режим і тип (включаючи той факт, що це символьна посилання) в дереві об'єкта, який представляє його каталог, що містить.

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

Якщо ви видалите файл, на який посилається symlink, він жодним чином не впливає на керовану Git символьну посилання. У вас буде звисаюча довідка. Користувач повинен або видалити, або змінити посилання, щоб вказати на щось дійсне, якщо потрібно.


328
До речі. Якщо ви перебуваєте у файловій системі на зразок FAT, яка не підтримує символічні посилання, і ваш сховище використовує їх, ви можете встановити core.symlinksзмінну конфігурації на хибну, а символьні посилання перевірятимуться як невеликі текстові файли, що містять текст посилання.
Якуб Нарубський

14
@ JakubNarębski Я бачив це раніше. У нашому репо було текстовий файл з одним рядком, шлях до бібліотеки, яку ми використовуємо. Не міг зрозуміти, яка мета була. Зараз я знаю, що сталося.
Метт К

25
Я не вагаюся коментувати відповідь з високою швидкістю, але я думаю, що фраза «так, як це було б для звичайного файлу» може ввести в оману для новачків.
Меттью Ганніган

10
(закінчився час редагування) Це як звичайний файл лише тим, що вміст знаходиться в краплі. Критична відмінність полягає в тому, що для нормального файлу крапка є вмістом файлу, але для симпосилання - це ім'я файлу, на який він посилається. @ JakubNarębski Щодо "невеликих текстових файлів". Ви сподіваєтесь, що вони маленькі та текстові, але, звичайно, крапля - це крапля і, можливо, може бути величезною та двійковою. Дивіться stackoverflow.com/questions/18411200/… про те, коли файл неправильно вводиться як символьне посилання.
Меттью Ганніган

2
Не забудьте перевірити ваші глобальні налаштування щодо символьних посилань та локальних параметрів для посилань. Якщо налаштування були скопійовані з TortiseGit або Windows, то ви могли б symlinks = falseз ними возитися.
фіат

250

Ви можете дізнатися, що 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 зберігає його вміст у магазині об'єктів Git.

$ git add ./symlink

Отже, що було додано?

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

Хеш - це посилання на упакований об’єкт, створений у магазині об'єктів Git. Ви можете вивчити цей об’єкт, якщо заглянете в .git/objects/15/96f9db1b9610f238b78dd168ae33faa2dec15cкорінь вашого сховища. Це файл, який Git зберігає у сховищі, який ви згодом можете перевірити. Якщо ви вивчите цей файл, ви побачите, що він дуже маленький. Він не зберігає вміст пов'язаного файлу.

(Примітка 120000- це режим, вказаний у ls-filesвихідному документі. Це буде щось на зразок 100644звичайного файлу.)

Але що робить Git з цим об'єктом, коли ви перевіряєте його з сховища та у вашу файлову систему? Це залежить від core.symlinksконфігурації. Від man git-config:

core.symlinks

Якщо помилкові, символьні посилання перевіряються як невеликі прості файли, що містять текст посилання.

Отже, із символічним посиланням у сховищі, після оформлення замовлення ви отримуєте текстовий файл із посиланням на повний шлях файлової системи, або власне символічне посилання залежно від значення core.symlinksконфігурації.

Так чи інакше, дані, на які посилається симпосилання, не зберігаються у сховищі.


1
Страхітлива відповідь
CervEd

147

Примітка "Редактора": Ця публікація може містити застарілу інформацію. Будь ласка, дивіться коментарі та це запитання щодо змін у Git з 1.6.1.

Symlinked каталоги:

Важливо зазначити, що відбувається, коли є каталог, який є м'яким посиланням. Будь-яке потягнення 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 pullAND знайдено кілька оновлень

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

4
Варто зазначити, що ці застереження щодо каталогів, що зв'язані між собою , не стосуються версійних посилань. Основним кращим випадком, про який йдеться, було те, що люди, що символізують деяке чи все робоче дерево у інший шлях (скажімо, на інший розділ з більшою кількістю дискового простору) і очікують, що Git перевірить код через існуючу посилання. Тобто, якщо у вас є проект, який містить перетворені символьні посилання на файли чи каталоги, нормальна поведінка symlink-as-blob збереже символьні посилання, правильно змінить версію цих посилань і в іншому випадку працюватиме, як очікувалося.
Джон Вітлі

Вищеописана поведінка тестована на git 1.6.5.6; але я сильно підозрюю, що поведінка з розумом була правильною в git досить довгий час.
Джон Вітлі

22
Чи є така поведінка у всіх версіях git чи це було виправлено?
jbotnik

24
Схоже, така поведінка виправлена ​​зараз, див. stackoverflow.com/a/1943656/1334781
Рон Wertlen

2
Шекар: Чи будете ви редагувати свою відповідь, щоб відобразити зміни в git за останні роки?
einpoklum
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.